From 0ad0c6c7ded870ac50530a9e684d74c2bb12ec70 Mon Sep 17 00:00:00 2001 From: Giulio Romualdi Date: Mon, 6 Oct 2025 09:57:06 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20Remove=20duplicated=20C?= =?UTF-8?q?olorPalette=20class=20and=20related=20matplotlib=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robot_log_visualizer/plotter/color_palette.py | 39 --------- .../plotter/pyqtgraph_viewer_canvas.py | 5 +- robot_log_visualizer/utils/utils.py | 87 ++++++++++++------- setup.cfg | 1 - 4 files changed, 59 insertions(+), 73 deletions(-) delete mode 100644 robot_log_visualizer/plotter/color_palette.py diff --git a/robot_log_visualizer/plotter/color_palette.py b/robot_log_visualizer/plotter/color_palette.py deleted file mode 100644 index e1ec87c..0000000 --- a/robot_log_visualizer/plotter/color_palette.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (C) 2024 Istituto Italiano di Tecnologia (IIT). All rights reserved. -# This software may be modified and distributed under the terms of the -# Released under the terms of the BSD 3-Clause License - -import matplotlib.pyplot as plt - - -class ColorPalette: - def __init__(self): - # Define the color taking from the default matplotlib color palette - # prop_cycle provides the color cycle used as rcParams. In the future, - # if one wants to change the default color palette in Matplotlib, - # they can modify the set rcParams directly and our color_palette will - # always take the one set See here: matplotlib.org/stable/users/explain/customizing.html. - # For details on prop_cycle, visit: matplotlib.org/stable/users/explain/artists/color_cycle.html - self.colors = [ - color["color"] for color in list(plt.rcParams["axes.prop_cycle"]) - ] - - self.current_index = 0 - - def get_color(self, index): - return self.colors[index % len(self.colors)] - - def __iter__(self): - self.current_index = 0 - return self - - def __len__(self): - return len(self.colors) - - def __next__(self): - color = self.get_color(self.current_index) - self.current_index += 1 - - return color - - def __call__(self, index): - return self.get_color(index) diff --git a/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py b/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py index 7704f31..c8acaac 100644 --- a/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py +++ b/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py @@ -10,7 +10,7 @@ import pyqtgraph as pg # type: ignore from qtpy import QtCore, QtWidgets # type: ignore -from robot_log_visualizer.plotter.color_palette import ColorPalette +from robot_log_visualizer.utils.utils import ColorPalette from robot_log_visualizer.signal_provider.signal_provider import ProviderType # ------------------------------------------------------------------------ @@ -190,7 +190,8 @@ def _add_missing_curves( y = data["data"][:] x = data["timestamps"] - self._signal_provider.initial_time - pen = pg.mkPen(next(self._palette), width=2) + palette_color = next(self._palette) + pen = pg.mkPen(palette_color.as_hex(), width=2) self._curves[key] = self._plot.plot( x, diff --git a/robot_log_visualizer/utils/utils.py b/robot_log_visualizer/utils/utils.py index f46f68c..0c465e8 100644 --- a/robot_log_visualizer/utils/utils.py +++ b/robot_log_visualizer/utils/utils.py @@ -2,6 +2,8 @@ # This software may be modified and distributed under the terms of the # Released under the terms of the BSD 3-Clause License +from __future__ import annotations + from enum import Enum @@ -19,63 +21,86 @@ def __init__(self): class Color: - """ - Color class to handle color in different formats - """ + """Utility class representing a colour with handy conversions.""" - def __init__(self, hex="#000000"): + def __init__(self, hex: str = "#000000"): self.hex = hex - def as_hex(self): + def as_hex(self) -> str: return self.hex - def as_rgb(self): + def as_rgb(self) -> tuple[int, int, int]: return self.hex_to_rgb(self.hex) - def as_normalized_rgb(self): + def as_normalized_rgb(self) -> tuple[float, float, float]: return self.get_to_normalized_rgb(self.hex) @staticmethod - def hex_to_rgb(hex): + def hex_to_rgb(hex_value: str) -> tuple[int, int, int]: # https://stackoverflow.com/questions/29643352/converting-hex-to-rgb-value-in-python - hex = hex.lstrip("#") - hlen = len(hex) - return tuple(int(hex[i : i + hlen // 3], 16) for i in range(0, hlen, hlen // 3)) + hex_value = hex_value.lstrip("#") + hlen = len(hex_value) + return tuple( + int(hex_value[i : i + hlen // 3], 16) + for i in range(0, hlen, hlen // 3) + ) @staticmethod - def get_to_normalized_rgb(hex): - rgb = Color.hex_to_rgb(hex) + def get_to_normalized_rgb(hex_value: str) -> tuple[float, float, float]: + rgb = Color.hex_to_rgb(hex_value) return (rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0) +DEFAULT_COLOR_CYCLE = ( + "#1f77b4", # blue + "#ff7f0e", # orange + "#2ca02c", # green + "#d62728", # red + "#9467bd", # purple + "#8c564b", # brown + "#e377c2", # pink + "#7f7f7f", # gray + "#bcbd22", # olive + "#17becf", # cyan +) + + class ColorPalette: - """ - Color palette class to handle color palette. - The user can get a color from the palette and the palette will automatically - cycle through the colors. + """Cycling palette yielding :class:`Color` objects. + + Args: + colors: Optional iterable of colour specifications (hex strings or + :class:`Color` instances). When omitted, ``DEFAULT_COLOR_CYCLE`` is + used. """ - def __init__(self): - # use matlab color palette + def __init__(self, colors=None): + palette = colors or DEFAULT_COLOR_CYCLE + self._color_palette = [ - Color("#0072BD"), - Color("#D95319"), - Color("#EDB120"), - Color("#7E2F8E"), - Color("#77AC30"), - Color("#4DBEEE"), - Color("#A2142F"), - Color("#7E2F8E"), - Color("#77AC30"), - Color("#4DBEEE"), - Color("#A2142F"), + color if isinstance(color, Color) else Color(str(color)) + for color in palette ] + + if not self._color_palette: + raise ValueError("ColorPalette requires at least one colour") + self._index = 0 def __iter__(self): + self._index = 0 return self - def __next__(self): + def __next__(self) -> Color: color = self._color_palette[self._index] self._index = (self._index + 1) % len(self._color_palette) return color + + def __len__(self) -> int: + return len(self._color_palette) + + def __call__(self, index: int) -> Color: + return self._color_palette[index % len(self._color_palette)] + + def reset(self) -> None: + self._index = 0 diff --git a/setup.cfg b/setup.cfg index 0d9cb5c..1302eae 100644 --- a/setup.cfg +++ b/setup.cfg @@ -46,7 +46,6 @@ install_requires = PySide2 qtpy pyqtconsole - matplotlib h5py pyqtgraph include_package_data = True