use std::sync::Arc;
use serde::{Deserialize, Serialize};
use pluot_core::{maybe_timeout, FutureExt, Duration};
use pluot_core::log;
use pluot_core::wgpu;
use pluot_core::cache::{use_memo_vec_f32, use_memo_vec_string};
use pluot_core::zarr::is_timed_out_zarrs_error;
use zarrs::storage::AsyncReadableStorageTraits;
use pluot_core::two::svg::{update_svg, SvgContext};
use pluot_core::render_traits::{ColorMode, DrawToRasterCpu, DrawToRasterGpu, DrawToSvg, MarginParams, PickableLayer, PreparedAndDraw, PreparedLayer, UnitsMode, ViewParams, resolve_store_name};
use pluot_core::render_types::{CpuContext, CpuRenderPass, PrepareResult};
use pluot_core::render_types::GpuContext;
use pluot_core::d3::scale::{ScaleBand, Scaleable};
use pluot_core::composite_layers::bar_plot_layer::{BarOrientation, BarPlotLayer, BarPlotLayerParams};
use pluot_core::LayerPickingResult;
use pluot_core::viewport::DataCoord;
use pluot_core::viewport::ScreenCoord;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
pub struct ZarrBarPlotLayerParams {
pub layer_id: String,
pub bounds: Option<MarginParams>,
pub orientation: BarOrientation,
pub store_name: Option<String>,
pub identifier_key: String,
pub quantity_key: String,
pub fill_color: Option<ColorMode>,
}
impl Default for ZarrBarPlotLayerParams {
fn default() -> Self {
Self {
layer_id: "".to_string(),
bounds: None,
orientation: BarOrientation::Vertical,
store_name: None,
identifier_key: "".to_string(),
quantity_key: "".to_string(),
fill_color: None,
}
}
}
pub struct ZarrBarPlotLayer {
view_params: ViewParams,
layer_params: ZarrBarPlotLayerParams,
store: Arc<dyn AsyncReadableStorageTraits>,
store_name: String,
inner: Option<BarPlotLayer>,
}
impl ZarrBarPlotLayer {
pub fn new(view_params: ViewParams, layer_params: ZarrBarPlotLayerParams) -> Self {
let store_name = resolve_store_name(&layer_params.store_name, &view_params);
let store = view_params.get_store(&store_name);
Self {
view_params,
layer_params,
store,
store_name,
inner: None,
}
}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl PreparedLayer for ZarrBarPlotLayer {
async fn prepare(&mut self, gpu_context: Option<&GpuContext<'_>>) -> PrepareResult {
let store = self.store.clone();
let cat_future_deps = vec!["cat_bytes".to_string(), self.store_name.clone(), self.layer_params.layer_id.to_string()];
let cat_future = use_memo_vec_string(async || {
let array_path = &self.layer_params.identifier_key;
let array = zarrs::array::Array::async_open(store.clone(), array_path).await.unwrap();
let subset = array.subset_all();
let values = array.async_retrieve_array_subset::<Vec<String>>(&subset).await?;
Ok(values)
}, &cat_future_deps, self.view_params.cache_enabled);
let quant_future_deps = vec!["quant_bytes".to_string(), self.store_name.clone(), self.layer_params.layer_id.clone(), self.layer_params.quantity_key.clone()];
let quant_future = use_memo_vec_f32(async || {
let array_path = &self.layer_params.quantity_key;
let array = zarrs::array::Array::async_open(store.clone(), array_path).await.unwrap();
let subset = array.subset_all();
let values = array.async_retrieve_array_subset::<Vec<i64>>(&subset).await?;
let f32_values: Vec<f32> = values.iter().map(|&v| v as f32).collect();
Ok(f32_values)
}, &quant_future_deps, self.view_params.cache_enabled);
let futures_try_join_result = futures::try_join!(
maybe_timeout!(cat_future, self.view_params.timeout),
maybe_timeout!(quant_future, self.view_params.timeout),
);
let (cat_arr, quant_arr) = match futures_try_join_result {
Ok((cat_result, quant_result)) => {
match (cat_result, quant_result) {
(Ok(c), Ok(q)) => (c, q),
(Err(e), _) | (_, Err(e)) => {
if is_timed_out_zarrs_error(&e) {
return PrepareResult { bailed_early: true };
} else {
panic!("Zarrs error during ZarrBarLayer prepare: {:?}", e);
}
}
}
}
Err(_) => {
return PrepareResult { bailed_early: true };
}
};
let mut sublayer = BarPlotLayer::new(
self.view_params.clone(),
BarPlotLayerParams {
layer_id: format!("{}_bar_plot_sublayer", self.layer_params.layer_id),
bounds: self.layer_params.bounds.clone(),
orientation: self.layer_params.orientation.clone(),
data_unit_mode_for_identifier_dim: UnitsMode::Pixels,
data_unit_mode_for_quantity_dim: UnitsMode::Data,
identifier: cat_arr,
quantity: quant_arr,
fill_color: self.layer_params.fill_color.clone(),
}
);
sublayer.prepare(gpu_context).await;
self.inner = Some(sublayer);
return PrepareResult {
bailed_early: false,
};
}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl DrawToRasterGpu for ZarrBarPlotLayer {
async fn draw(&self, gpu_context: &GpuContext<'_>, pass: &mut wgpu::RenderPass) {
if let Some(inner) = &self.inner {
DrawToRasterGpu::draw(inner, gpu_context, pass).await;
}
}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl DrawToRasterCpu for ZarrBarPlotLayer {
async fn draw(&self, _cpu_context: &CpuContext<'_>, _pass: &mut CpuRenderPass) {}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl DrawToSvg for ZarrBarPlotLayer {
async fn draw(&self, ctx: &mut SvgContext) {
if let Some(inner) = &self.inner {
DrawToSvg::draw(inner, ctx).await
}
}
}
impl PickableLayer for ZarrBarPlotLayer {
fn pick(&self, screen_coord: ScreenCoord, data_coord: Option<DataCoord>) -> Option<LayerPickingResult> {
let DataCoord::TwoD { x: cx, y: cy } = data_coord? else {
return None;
};
if let Some(inner) = &self.inner {
return PickableLayer::pick(inner, screen_coord, data_coord);
}
return None;
}
}