Source code for whitecanvas.backend.plotly.bars

from __future__ import annotations

import numpy as np
from numpy.typing import NDArray
from whitecanvas.protocols import BarProtocol, check_protocol
from whitecanvas.types import FacePattern
from whitecanvas.utils.normalize import rgba_str_color, arr_color
from ._base import PlotlyLayer
from whitecanvas.backend import _not_implemented


[docs]@check_protocol(BarProtocol) class Bars(PlotlyLayer): def __init__(self, xlow, xhigh, ylow, yhigh): x = (xlow + xhigh) / 2 ndata = len(x) self._props = { "x": x, "y": yhigh - ylow, "width": xhigh - xlow, "base": ylow, "marker": { "color": ["blue"] * ndata, "pattern": { "shape": "-", }, "line": { "width": [1] * ndata, "color": ["blue"] * ndata, }, }, "visible": True, "showlegend": False, "type": "bar", } ##### XXYYDataProtocol ##### def _plt_get_data(self): half_width = self._props["width"] / 2 x = self._props["x"] yhigh = self._props["y"] # for some reason, the base property is dtype=object ylow = self._props["base"].astype(yhigh.dtype, copy=False) xlow = x - half_width / 2 xhigh = x + half_width / 2 return xlow, xhigh, ylow, yhigh def _plt_set_data(self, x0, x1, y0, y1): self._props["x"] = (x0 + x1) / 2 self._props["y"] = y1 - y0 self._props["width"] = x1 - x0 self._props["base"] = y0 def _plt_get_ndata(self): return len(self._props["x"]) def _plt_get_face_color(self) -> NDArray[np.float32]: color = self._props["marker"]["color"] if len(color) == 0: return np.empty((0, 4), dtype=np.float32) return np.stack([arr_color(c) for c in color], axis=0) def _plt_set_face_color(self, color: NDArray[np.float32]): if color.ndim == 1: color = [rgba_str_color(color)] * self._plt_get_ndata() else: color = [rgba_str_color(c) for c in color] self._props["marker"]["color"] = color def _plt_get_face_pattern(self) -> list[FacePattern]: return [FacePattern(p) for p in self._props["marker"]["pattern"]["shape"]] def _plt_set_face_pattern(self, pattern: FacePattern | list[FacePattern]): if isinstance(pattern, FacePattern): ptn = [pattern.value] * self._plt_get_ndata() else: ptn = [ptn.value for ptn in pattern] self._props["marker"]["pattern"]["shape"] = ptn ##### HasEdges protocol ##### def _plt_get_edge_width(self) -> NDArray[np.floating]: return np.array(self._props["marker"]["line"]["width"]) def _plt_set_edge_width(self, width: float): if np.isscalar(width): width = np.full(self._plt_get_ndata(), width) self._props["marker"]["line"]["width"] = width _plt_get_edge_style, _plt_set_edge_style = _not_implemented.edge_styles() def _plt_get_edge_color(self) -> NDArray[np.float32]: color = self._props["marker"]["line"]["color"] if len(color) == 0: return np.empty((0, 4), dtype=np.float32) return np.stack([arr_color(c) for c in color], axis=0) def _plt_set_edge_color(self, color: NDArray[np.float32]): if color.ndim == 1: color = [rgba_str_color(color)] * self._plt_get_ndata() else: color = [rgba_str_color(c) for c in color] self._props["marker"]["line"]["color"] = color