from __future__ import annotations
import numpy as np
from numpy.typing import NDArray
from vispy.scene import visuals
from whitecanvas.types import Alignment, FacePattern, LineStyle
from whitecanvas.protocols import TextProtocol, check_protocol
from whitecanvas.utils.normalize import as_color_array
from whitecanvas.backend import _not_implemented
[docs]@check_protocol(TextProtocol)
class Texts(visuals.Compound):
def __init__(
self, x: NDArray[np.floating], y: NDArray[np.floating], text: list[str]
):
super().__init__(
[SingleText(x0, y0, text0) for x0, y0, text0 in zip(x, y, text)]
)
@property
def subvisuals(self) -> list[SingleText]:
return self._subvisuals
def _plt_get_visible(self) -> bool:
return self.visible
def _plt_set_visible(self, visible: bool):
self.visible = visible
##### TextProtocol #####
def _plt_get_text(self) -> list[str]:
return [t.text for t in self.subvisuals]
def _plt_set_text(self, text: list[str]):
for t, text0 in zip(self.subvisuals, text):
t.text = text0
def _plt_get_text_color(self):
return np.array([t.color for t in self.subvisuals])
def _plt_set_text_color(self, color):
color = as_color_array(color, len(self.subvisuals))
for t, color0 in zip(self.subvisuals, color):
t.color = color0
def _plt_get_text_size(self) -> float:
return [t.font_size for t in self.subvisuals]
def _plt_set_text_size(self, size: float | NDArray[np.floating]):
if isinstance(size, (int, float, np.number)):
size = np.full(len(self.subvisuals), size)
for t, size0 in zip(self.subvisuals, size):
t.font_size = size0
def _plt_get_text_position(
self,
) -> tuple[NDArray[np.floating], NDArray[np.floating]]:
return tuple(np.array(t.pos[0, 1:]) for t in self.subvisuals)
def _plt_set_text_position(
self, position: tuple[NDArray[np.floating], NDArray[np.floating]]
):
for t, x0, y0 in zip(self.subvisuals, *position):
t.pos = x0, y0
def _plt_get_text_anchor(self) -> list[Alignment]:
return [t._alignment for t in self.subvisuals]
def _plt_set_text_anchor(self, anc: Alignment | list[Alignment]):
if isinstance(anc, Alignment):
anc = [anc] * len(self.subvisuals)
for t, anc0 in zip(self.subvisuals, anc):
va, ha = anc0.split()
t.anchors = va.value, ha.value
t._alignment = anc0
def _plt_get_text_rotation(self) -> float:
return np.array([t.rotation[0] for t in self.subvisuals])
def _plt_set_text_rotation(self, rotation: float | NDArray[np.floating]):
if isinstance(rotation, (int, float, np.number)):
rotation = np.full(len(self.subvisuals), rotation)
for t, rotation0 in zip(self.subvisuals, rotation):
t.rotation = rotation0
def _plt_get_text_fontfamily(self) -> list[str]:
return [t.face for t in self.subvisuals]
def _plt_set_text_fontfamily(self, fontfamily: str | list[str]):
if isinstance(fontfamily, str):
fontfamily = [fontfamily] * len(self.subvisuals)
for t, fontfamily0 in zip(self.subvisuals, fontfamily):
t.face = fontfamily0
def _plt_get_face_color(self):
return np.zeros((len(self.subvisuals), 4))
def _plt_set_face_color(self, color):
pass
_plt_get_face_pattern, _plt_set_face_pattern = _not_implemented.face_patterns()
def _plt_get_edge_color(self):
return np.zeros((len(self.subvisuals), 4))
def _plt_set_edge_color(self, color):
pass
def _plt_get_edge_width(self) -> float:
return np.zeros(len(self.subvisuals))
def _plt_set_edge_width(self, width: float | NDArray[np.floating]):
pass
def _plt_get_edge_style(self) -> LineStyle:
return [LineStyle.SOLID] * len(self.subvisuals)
def _plt_set_edge_style(self, style: LineStyle | list[LineStyle]):
pass
[docs]class SingleText(visuals.Text):
def __init__(self, x: float, y: float, text: str):
super().__init__(text=text, anchor_x="left", anchor_y="bottom")
self._plt_set_text_position([x, y])
self.unfreeze()
self._alignment = Alignment.BOTTOM_LEFT
##### BaseProtocol #####
def _plt_get_visible(self) -> bool:
return self.visible
def _plt_set_visible(self, visible: bool):
self.visible = visible
##### TextProtocol #####
def _plt_get_text(self) -> str:
return self.text
def _plt_set_text(self, text: str):
self.text = text
def _plt_get_text_color(self):
return self.color
def _plt_set_text_color(self, color):
self.color = color
def _plt_get_text_size(self) -> float:
return self.font_size
def _plt_set_text_size(self, size: float):
self.font_size = size
def _plt_get_text_position(self) -> tuple[float, float]:
return tuple(self.pos[0, 1:])
def _plt_set_text_position(self, position: tuple[float, float]):
self.pos = position
def _plt_get_text_anchor(self) -> Alignment:
return self._alignment
def _plt_set_text_anchor(self, anc: Alignment):
va, ha = anc.split()
self.anchors = va.value, ha.value
self._alignment = anc
def _plt_get_text_rotation(self) -> float:
return self.rotation[0]
def _plt_set_text_rotation(self, rotation: float):
self.rotation = rotation
def _plt_get_text_fontfamily(self) -> str:
return self.face
def _plt_set_text_fontfamily(self, fontfamily: str):
self.face = fontfamily