mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 11:11:49 +02:00
feat(utils.colors): general color validators
This commit is contained in:
@ -1,11 +1,14 @@
|
||||
import re
|
||||
from typing import Literal
|
||||
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from pydantic_core import PydanticCustomError
|
||||
from qtpy.QtGui import QColor
|
||||
|
||||
|
||||
class Colors:
|
||||
|
||||
@staticmethod
|
||||
def golden_ratio(num: int) -> list:
|
||||
"""Calculate the golden ratio for a given number of angles.
|
||||
@ -63,3 +66,211 @@ class Colors:
|
||||
else:
|
||||
raise ValueError("Unsupported format. Please choose 'RGB', 'HEX', or 'QColor'.")
|
||||
return colors
|
||||
|
||||
@staticmethod
|
||||
def validate_color(color: tuple | str) -> tuple | str:
|
||||
"""
|
||||
Validate the color input if it is HEX or RGBA compatible. Can be used in any pydantic model as a field validator.
|
||||
|
||||
Args:
|
||||
color(tuple|str): The color to be validated. Can be a tuple of RGBA values or a HEX string.
|
||||
|
||||
Returns:
|
||||
tuple|str: The validated color.
|
||||
"""
|
||||
CSS_COLOR_NAMES = {
|
||||
"aliceblue",
|
||||
"antiquewhite",
|
||||
"aqua",
|
||||
"aquamarine",
|
||||
"azure",
|
||||
"beige",
|
||||
"bisque",
|
||||
"black",
|
||||
"blanchedalmond",
|
||||
"blue",
|
||||
"blueviolet",
|
||||
"brown",
|
||||
"burlywood",
|
||||
"cadetblue",
|
||||
"chartreuse",
|
||||
"chocolate",
|
||||
"coral",
|
||||
"cornflowerblue",
|
||||
"cornsilk",
|
||||
"crimson",
|
||||
"cyan",
|
||||
"darkblue",
|
||||
"darkcyan",
|
||||
"darkgoldenrod",
|
||||
"darkgray",
|
||||
"darkgreen",
|
||||
"darkgrey",
|
||||
"darkkhaki",
|
||||
"darkmagenta",
|
||||
"darkolivegreen",
|
||||
"darkorange",
|
||||
"darkorchid",
|
||||
"darkred",
|
||||
"darksalmon",
|
||||
"darkseagreen",
|
||||
"darkslateblue",
|
||||
"darkslategray",
|
||||
"darkslategrey",
|
||||
"darkturquoise",
|
||||
"darkviolet",
|
||||
"deeppink",
|
||||
"deepskyblue",
|
||||
"dimgray",
|
||||
"dimgrey",
|
||||
"dodgerblue",
|
||||
"firebrick",
|
||||
"floralwhite",
|
||||
"forestgreen",
|
||||
"fuchsia",
|
||||
"gainsboro",
|
||||
"ghostwhite",
|
||||
"gold",
|
||||
"goldenrod",
|
||||
"gray",
|
||||
"green",
|
||||
"greenyellow",
|
||||
"grey",
|
||||
"honeydew",
|
||||
"hotpink",
|
||||
"indianred",
|
||||
"indigo",
|
||||
"ivory",
|
||||
"khaki",
|
||||
"lavender",
|
||||
"lavenderblush",
|
||||
"lawngreen",
|
||||
"lemonchiffon",
|
||||
"lightblue",
|
||||
"lightcoral",
|
||||
"lightcyan",
|
||||
"lightgoldenrodyellow",
|
||||
"lightgray",
|
||||
"lightgreen",
|
||||
"lightgrey",
|
||||
"lightpink",
|
||||
"lightsalmon",
|
||||
"lightseagreen",
|
||||
"lightskyblue",
|
||||
"lightslategray",
|
||||
"lightslategrey",
|
||||
"lightsteelblue",
|
||||
"lightyellow",
|
||||
"lime",
|
||||
"limegreen",
|
||||
"linen",
|
||||
"magenta",
|
||||
"maroon",
|
||||
"mediumaquamarine",
|
||||
"mediumblue",
|
||||
"mediumorchid",
|
||||
"mediumpurple",
|
||||
"mediumseagreen",
|
||||
"mediumslateblue",
|
||||
"mediumspringgreen",
|
||||
"mediumturquoise",
|
||||
"mediumvioletred",
|
||||
"midnightblue",
|
||||
"mintcream",
|
||||
"mistyrose",
|
||||
"moccasin",
|
||||
"navajowhite",
|
||||
"navy",
|
||||
"oldlace",
|
||||
"olive",
|
||||
"olivedrab",
|
||||
"orange",
|
||||
"orangered",
|
||||
"orchid",
|
||||
"palegoldenrod",
|
||||
"palegreen",
|
||||
"paleturquoise",
|
||||
"palevioletred",
|
||||
"papayawhip",
|
||||
"peachpuff",
|
||||
"peru",
|
||||
"pink",
|
||||
"plum",
|
||||
"powderblue",
|
||||
"purple",
|
||||
"red",
|
||||
"rosybrown",
|
||||
"royalblue",
|
||||
"saddlebrown",
|
||||
"salmon",
|
||||
"sandybrown",
|
||||
"seagreen",
|
||||
"seashell",
|
||||
"sienna",
|
||||
"silver",
|
||||
"skyblue",
|
||||
"slateblue",
|
||||
"slategray",
|
||||
"slategrey",
|
||||
"snow",
|
||||
"springgreen",
|
||||
"steelblue",
|
||||
"tan",
|
||||
"teal",
|
||||
"thistle",
|
||||
"tomato",
|
||||
"turquoise",
|
||||
"violet",
|
||||
"wheat",
|
||||
"white",
|
||||
"whitesmoke",
|
||||
"yellow",
|
||||
"yellowgreen",
|
||||
}
|
||||
if isinstance(color, str):
|
||||
hex_pattern = re.compile(r"^#(?:[0-9a-fA-F]{3}){1,2}$")
|
||||
if hex_pattern.match(color):
|
||||
return color
|
||||
elif color.lower() in CSS_COLOR_NAMES:
|
||||
return color
|
||||
else:
|
||||
raise PydanticCustomError(
|
||||
"unsupported color",
|
||||
"The color must be a valid HEX string or CSS Color.",
|
||||
{"wrong_value": color},
|
||||
)
|
||||
elif isinstance(color, tuple):
|
||||
if len(color) != 4:
|
||||
raise PydanticCustomError(
|
||||
"unsupported color",
|
||||
"The color must be a tuple of 4 elements (R, G, B, A).",
|
||||
{"wrong_value": color},
|
||||
)
|
||||
for value in color:
|
||||
if not 0 <= value <= 255:
|
||||
raise PydanticCustomError(
|
||||
"unsupported color",
|
||||
f"The color values must be between 0 and 255. Provide color {color}.",
|
||||
{"wrong_value": color},
|
||||
)
|
||||
return color
|
||||
|
||||
@staticmethod
|
||||
def validate_color_map(color_map: str) -> str:
|
||||
"""
|
||||
Validate the colormap input if it is supported by pyqtgraph. Can be used in any pydantic model as a field validator. If validation fails it prints all available colormaps from pyqtgraph instance.
|
||||
|
||||
Args:
|
||||
color_map(str): The colormap to be validated.
|
||||
|
||||
Returns:
|
||||
str: The validated colormap.
|
||||
"""
|
||||
available_colormaps = pg.colormap.listMaps()
|
||||
if color_map not in available_colormaps:
|
||||
raise PydanticCustomError(
|
||||
"unsupported colormap",
|
||||
f"Colormap '{color_map}' not found in the current installation of pyqtgraph. Choose on the following: {available_colormaps}.",
|
||||
{"wrong_value": color_map},
|
||||
)
|
||||
return color_map
|
||||
|
@ -7,7 +7,7 @@ from pydantic import BaseModel, Field, field_validator
|
||||
from pydantic_core import PydanticCustomError
|
||||
from qtpy import QtCore
|
||||
|
||||
from bec_widgets.utils import BECConnector, ConnectionConfig
|
||||
from bec_widgets.utils import BECConnector, ConnectionConfig, Colors
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bec_widgets.widgets.figure.plots.waveform import BECWaveform1D
|
||||
@ -37,9 +37,11 @@ class Signal(BaseModel):
|
||||
class CurveConfig(ConnectionConfig):
|
||||
parent_id: Optional[str] = Field(None, description="The parent plot of the curve.")
|
||||
label: Optional[str] = Field(None, description="The label of the curve.")
|
||||
color: Optional[Any] = Field(None, description="The color of the curve.")
|
||||
color: Optional[str | tuple] = Field(None, description="The color of the curve.")
|
||||
symbol: Optional[str] = Field("o", description="The symbol of the curve.")
|
||||
symbol_color: Optional[str] = Field(None, description="The color of the symbol of the curve.")
|
||||
symbol_color: Optional[str | tuple] = Field(
|
||||
None, description="The color of the symbol of the curve."
|
||||
)
|
||||
symbol_size: Optional[int] = Field(5, description="The size of the symbol of the curve.")
|
||||
pen_width: Optional[int] = Field(2, description="The width of the pen of the curve.")
|
||||
pen_style: Optional[Literal["solid", "dash", "dot", "dashdot"]] = Field(
|
||||
@ -50,19 +52,12 @@ class CurveConfig(ConnectionConfig):
|
||||
color_map_z: Optional[str] = Field(
|
||||
"plasma", description="The colormap of the curves z gradient.", validate_default=True
|
||||
)
|
||||
|
||||
model_config: dict = {"validate_assignment": True}
|
||||
|
||||
@field_validator("color_map_z")
|
||||
def validate_color_map(cls, v, values):
|
||||
if v is not None and v != "":
|
||||
available_colormaps = pg.colormap.listMaps()
|
||||
if v not in available_colormaps:
|
||||
raise PydanticCustomError(
|
||||
"unsupported colormap",
|
||||
f"Colormap '{v}' not found in the current installation of pyqtgraph. Choose on the following: {available_colormaps}.",
|
||||
{"wrong_value": v},
|
||||
)
|
||||
return v
|
||||
_validate_color_map_z = field_validator("color_map_z")(Colors.validate_color_map)
|
||||
_validate_color = field_validator("color")(Colors.validate_color)
|
||||
_validate_symbol_color = field_validator("symbol_color")(Colors.validate_color)
|
||||
|
||||
|
||||
class BECCurve(BECConnector, pg.PlotDataItem):
|
||||
|
@ -59,16 +59,7 @@ class SpiralProgressBarConfig(ConnectionConfig):
|
||||
)
|
||||
return v
|
||||
|
||||
@field_validator("color_map")
|
||||
def validate_color_map(cls, v, values):
|
||||
if v is not None and v != "":
|
||||
if v not in pg.colormap.listMaps():
|
||||
raise PydanticCustomError(
|
||||
"unsupported colormap",
|
||||
f"Colormap '{v}' not found in the current installation of pyqtgraph",
|
||||
{"wrong_value": v},
|
||||
)
|
||||
return v
|
||||
_validate_colormap = field_validator("color_map")(Colors.validate_color_map)
|
||||
|
||||
|
||||
class SpiralProgressBar(BECConnector, QWidget):
|
||||
|
Reference in New Issue
Block a user