Source code for graphinglib.graph_elements

from __future__ import annotations

from copy import deepcopy
from dataclasses import dataclass, field
from typing import Literal, Optional, Protocol

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import LineCollection
from numpy.typing import ArrayLike

from .legend_artists import VerticalLineCollection

try:
    from typing import Self
except ImportError:
    from typing_extensions import Self


class Plottable(Protocol):
    """
    Dummy class for a general plottable object.

    .. attention:: Not to be used directly.

    """

    def _plot_element(self, axes: plt.Axes, z_order: int, **kwargs) -> None:
        """
        Plots the element in the specified
        Axes
        """
        pass


class GraphingException(Exception):
    """
    General exception raised for the GraphingLib modules.
    """

    pass


[docs] class Hlines: """ This class implements simple horizontal lines. Parameters ---------- y : ArrayLike Vertical positions at which the lines should be plotted. x_min, x_max : ArrayLike Horizontal positions at which the lines should start and end. Different positions can be specified for each line. label : str, optional Label to be displayed in the legend. colors : list[str] Colors to use for the lines. One color for every line or a color per line can be specified. Default depends on the ``figure_style`` configuration. line_widths : list[float] Line widths to use for the lines. One width for every line or a width per line can be specified. Default depends on the ``figure_style`` configuration. line_styles : list[str] Line styles to use for the lines. One style for every line or a style per line can be specified. Default depends on the ``figure_style`` configuration. """
[docs] def __init__( self, y: ArrayLike, x_min: ArrayLike, x_max: ArrayLike, label: Optional[str] = None, colors: list[str] | str = "default", line_widths: list[float] | float = "default", line_styles: list[str] | str = "default", ) -> None: """ This class implements simple horizontal lines. Parameters ---------- y : ArrayLike Vertical positions at which the lines should be plotted. x_min, x_max : ArrayLike Horizontal positions at which the lines should start and end. Different positions can be specified for each line. label : str, optional Label to be displayed in the legend. colors : list[str] Colors to use for the lines. One color for every line or a color per line can be specified. Default depends on the ``figure_style`` configuration. line_widths : list[float] Line widths to use for the lines. One width for every line or a width per line can be specified. Default depends on the ``figure_style`` configuration. line_styles : list[str] Line styles to use for the lines. One style for every line or a style per line can be specified. Default depends on the ``figure_style`` configuration. """ if isinstance(y, (int, float)): self._y = y elif isinstance(y, (list, np.ndarray)): self._y = np.array(y) if isinstance(x_min, (int, float)): self._x_min = x_min elif isinstance(x_min, (list, np.ndarray)): self._x_min = np.array(x_min) if isinstance(x_max, (int, float)): self._x_max = x_max elif isinstance(x_max, (list, np.ndarray)): self._x_max = np.array(x_max) self._label = label self._colors = colors self._line_widths = line_widths self._line_styles = line_styles if isinstance(self._y, (int, float)) and isinstance( self._colors, (list, np.ndarray) ): raise GraphingException("There can't be multiple colors for a single line!") if isinstance(self._y, (int, float)) and isinstance( self._line_styles, (list, np.ndarray) ): raise GraphingException( "There can't be multiple line styles for a single line!" ) if isinstance(self._y, (int, float)) and isinstance( self._line_widths, (list, np.ndarray) ): raise GraphingException( "There can't be multiple line widths for a single line!" ) if ( isinstance(self._y, (list, np.ndarray)) and isinstance(self._colors, list) and isinstance(self._line_styles, list) and isinstance(self._line_widths, list) ): if ( len(self._y) != len(self._colors) or len(self._y) != len(self._line_styles) or len(self._y) != len(self._line_widths) ): raise GraphingException( "There must be the same number of colors, " + "line styles, line widths and lines!" )
@property def y(self) -> ArrayLike: return self._y @y.setter def y(self, y: ArrayLike) -> None: self._y = y @property def x_min(self) -> ArrayLike: return self._x_min @x_min.setter def x_min(self, x_min: ArrayLike) -> None: self._x_min = x_min @property def x_max(self) -> ArrayLike: return self._x_max @x_max.setter def x_max(self, x_max: ArrayLike) -> None: self._x_max = x_max @property def label(self) -> Optional[str]: return self._label @label.setter def label(self, label: Optional[str]) -> None: self._label = label @property def colors(self) -> list[str] | str: return self._colors @colors.setter def colors(self, colors: list[str] | str) -> None: self._colors = colors @property def line_widths(self) -> list[float] | float: return self._line_widths @line_widths.setter def line_widths(self, line_widths: list[float] | float) -> None: self._line_widths = line_widths @property def line_styles(self) -> list[str] | str: return self._line_styles @line_styles.setter def line_styles(self, line_styles: list[str] | str) -> None: self._line_styles = line_styles
[docs] def copy(self) -> Self: """ Returns a deep copy of the :class:`~graphinglib.graph_elements.Hlines` object. """ return deepcopy(self)
def _plot_element(self, axes: plt.Axes, z_order: int, **kwargs) -> None: """ Plots the element in the specified Axes Plots the element in the specified `Axes <https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.html>`_. """ if isinstance(self._y, list) and len(self._y) > 1: params = { "colors": self._colors, "linestyles": self._line_styles, "linewidths": self._line_widths, } params = {k: v for k, v in params.items() if v != "default"} axes.hlines( self._y, self._x_min, self._x_max, zorder=z_order, **params, ) params.pop("linewidths") self.handle = LineCollection( [[(0, 0)]] * (len(self._y) if len(self._y) <= 3 else 3), **params, ) else: params = { "colors": self._colors, "linestyles": self._line_styles, "linewidths": self._line_widths, } params = {k: v for k, v in params.items() if v != "default"} if isinstance(self._y, (int, float)): self.handle = LineCollection( [[(0, 0)]] * 1, **params, ) else: self.handle = LineCollection( [[(0, 0)]] * (len(self._y) if len(self._y) <= 3 else 3), **params, ) axes.hlines( self._y, self._x_min, self._x_max, zorder=z_order, **params, )
[docs] class Vlines: """ This class implements simple vertical lines. Parameters ---------- x : ArrayLike Horizontal positions at which the lines should be plotted. y_min, y_max : ArrayLike Vertical positions at which the lines should start and end. Different positions can be specified for each line. label : str, optional Label to be displayed in the legend. colors : list[str] Colors to use for the lines. One color for every line or a color per line can be specified. Default depends on the ``figure_style`` configuration. line_widths : list[float] Line widths to use for the lines. One width for every line or a width per line can be specified. Default depends on the ``figure_style`` configuration. line_styles : list[str] Line styles to use for the lines. One style for every line or a style per line can be specified. Default depends on the ``figure_style`` configuration. """
[docs] def __init__( self, x: ArrayLike, y_min: ArrayLike, y_max: ArrayLike, label: Optional[str] = None, colors: list[str] | str = "default", line_widths: list[float] | float = "default", line_styles: list[str] | str = "default", ) -> None: """ This class implements simple vertical lines. Parameters ---------- x : ArrayLike Horizontal positions at which the lines should be plotted. y_min, y_max : ArrayLike Vertical positions at which the lines should start and end. Different positions can be specified for each line. label : str, optional Label to be displayed in the legend. colors : list[str] Colors to use for the lines. One color for every line or a color per line can be specified. Default depends on the ``figure_style`` configuration. line_widths : list[float] Line widths to use for the lines. One width for every line or a width per line can be specified. Default depends on the ``figure_style`` configuration. line_styles : list[str] Line styles to use for the lines. One style for every line or a style per line can be specified. Default depends on the ``figure_style`` configuration. """ if isinstance(x, (int, float)): self._x = x elif isinstance(x, (list, np.ndarray)): self._x = np.array(x) if isinstance(y_min, (int, float)): self._y_min = y_min elif isinstance(y_min, (list, np.ndarray)): self._y_min = np.array(y_min) if isinstance(y_max, (int, float)): self._y_max = y_max elif isinstance(y_max, (list, np.ndarray)): self._y_max = np.array(y_max) self._label = label self._colors = colors self._line_styles = line_styles self._line_widths = line_widths if isinstance(self._x, (int, float)) and isinstance( self._colors, (list, np.ndarray) ): raise GraphingException("There can't be multiple colors for a single line!") if isinstance(self._x, (int, float)) and isinstance( self._line_styles, (list, np.ndarray) ): raise GraphingException( "There can't be multiple line styles for a single line!" ) if isinstance(self._x, (int, float)) and isinstance( self._line_widths, (list, np.ndarray) ): raise GraphingException( "There can't be multiple line widths for a single line!" ) if ( isinstance(self._x, (list, np.ndarray)) and isinstance(self._colors, list) and isinstance(self._line_styles, list) and isinstance(self._line_widths, list) ): if ( len(self._x) != len(self._colors) or len(self._x) != len(self._line_styles) or len(self._x) != len(self._line_widths) ): raise GraphingException( "There must be the same number of colors, " + "line styles, line widths and lines!" )
@property def x(self) -> ArrayLike: return self._x @x.setter def x(self, x: ArrayLike) -> None: self._x = x @property def y_min(self) -> ArrayLike: return self._y_min @y_min.setter def y_min(self, y_min: ArrayLike) -> None: self._y_min = y_min @property def y_max(self) -> ArrayLike: return self._y_max @y_max.setter def y_max(self, y_max: ArrayLike) -> None: self._y_max = y_max @property def label(self) -> Optional[str]: return self._label @label.setter def label(self, label: Optional[str]) -> None: self._label = label @property def colors(self) -> list[str] | str: return self._colors @colors.setter def colors(self, colors: list[str] | str) -> None: self._colors = colors @property def line_widths(self) -> list[float] | float: return self._line_widths @line_widths.setter def line_widths(self, line_widths: list[float] | float) -> None: self._line_widths = line_widths @property def line_styles(self) -> list[str] | str: return self._line_styles @line_styles.setter def line_styles(self, line_styles: list[str] | str) -> None: self._line_styles = line_styles
[docs] def copy(self) -> Self: """ Returns a deep copy of the :class:`~graphinglib.graph_elements.Vlines` object. """ return deepcopy(self)
def _plot_element(self, axes: plt.Axes, z_order: int, **kwargs) -> None: """ Plots the element in the specified `Axes <https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.html>`_. """ if isinstance(self._x, list) and len(self._x) > 1: params = { "colors": self._colors, "linestyles": self._line_styles, "linewidths": self._line_widths, } params = {k: v for k, v in params.items() if v != "default"} axes.vlines( self._x, self._y_min, self._y_max, zorder=z_order, **params, ) params.pop("linewidths") self.handle = VerticalLineCollection( [[(0, 0)]] * (len(self._x) if len(self._x) <= 4 else 4), **params, ) else: params = { "colors": self._colors, "linestyles": self._line_styles, "linewidths": self._line_widths, } params = {k: v for k, v in params.items() if v != "default"} self.handle = VerticalLineCollection( [[(0, 0)]] * (len(self._x) if len(self._x) <= 4 else 4), **params, ) axes.vlines( self._x, self._y_min, self._y_max, zorder=z_order, **params, )
[docs] class Point: """ This class implements a point object. The :class:`~graphinglib.graph_elements.Point` object can be used to show important coordinates in a plot or add a label to some point. Parameters ---------- x, y : float The x and y coordinates of the :class:`~graphinglib.graph_elements.Point`. label : str, optional Label to be attached to the :class:`~graphinglib.graph_elements.Point`. color : str or None Face color of the marker. Default depends on the ``figure_style`` configuration. edge_color : str or None Edge color of the marker. Default depends on the ``figure_style`` configuration. marker_size : float Size of the marker. Default depends on the ``figure_style`` configuration. marker_style : str Style of the marker. Default depends on the ``figure_style`` configuration. edge_width : float Edge width of the marker. Default depends on the ``figure_style`` configuration. font_size : float Font size for the text attached to the marker. Default depends on the ``figure_style`` configuration. text_color : str Color of the text attached to the marker. "same as point" uses the color of the point (prioritize edge color, then face color). Default depends on the ``figure_style`` configuration. h_align, v_align : str Horizontal and vertical alignment of the text attached to the :class:`~graphinglib.graph_elements.Point`. Defaults to bottom left. """
[docs] def __init__( self, x: float, y: float, label: Optional[str] = None, color: Optional[str] = "default", edge_color: Optional[str] = "default", marker_size: float | Literal["default"] = "default", marker_style: str = "default", edge_width: float | Literal["default"] = "default", font_size: int | Literal["same as figure"] = "same as figure", text_color: str = "default", h_align: str = "left", v_align: str = "bottom", ) -> None: """ This class implements a point object. The point object can be used to show important coordinates in a plot or add a label to some point. Parameters ---------- x, y : float The x and y coordinates of the :class:`~graphinglib.graph_elements.Point`. label : str, optional Label to be attached to the :class:`~graphinglib.graph_elements.Point`. color : str or None Face color of the marker. Default depends on the ``figure_style`` configuration. edge_color : str or None Edge color of the marker. Default depends on the ``figure_style`` configuration. marker_size : float Size of the marker. Default depends on the ``figure_style`` configuration. marker_style : str Style of the marker. Default depends on the ``figure_style`` configuration. edge_width : float Edge width of the marker. Default depends on the ``figure_style`` configuration. font_size : float Font size for the text attached to the marker. Default depends on the ``figure_style`` configuration. text_color : str Color of the text attached to the marker. "same as point" uses the color of the point (prioritize edge color, then face color). Default depends on the ``figure_style`` configuration. h_align, v_align : str Horizontal and vertical alignment of the text attached to the :class:`~graphinglib.graph_elements.Point`. Defaults to bottom left. """ if not isinstance(x, int | float) or not isinstance(y, int | float): raise GraphingException( "The x and y coordinates for a point must be a single number each!" ) else: self._x = x self._y = y self._label = label self._color = color self._edge_color = edge_color self._marker_size = marker_size self._marker_style = marker_style self._edge_width = edge_width self._font_size = font_size self._text_color = text_color self._h_align = h_align self._v_align = v_align self._show_coordinates: bool = False
@property def x(self) -> float: return self._x @x.setter def x(self, x: float) -> None: self._x = x @property def y(self) -> float: return self._y @y.setter def y(self, y: float) -> None: self._y = y @property def label(self) -> Optional[str]: return self._label @label.setter def label(self, label: Optional[str]) -> None: self._label = label @property def color(self) -> str | None: return self._color @color.setter def color(self, color: str) -> None: self._color = color @property def edge_color(self) -> str | None: return self._edge_color @edge_color.setter def edge_color(self, edge_color: str) -> None: self._edge_color = edge_color @property def marker_size(self) -> float | Literal["default"]: return self._marker_size @marker_size.setter def marker_size(self, marker_size: float | Literal["default"]) -> None: self._marker_size = marker_size @property def marker_style(self) -> str: return self._marker_style @marker_style.setter def marker_style(self, marker_style: str) -> None: self._marker_style = marker_style @property def edge_width(self) -> float | Literal["default"]: return self._edge_width @edge_width.setter def edge_width(self, edge_width: float | Literal["default"]) -> None: self._edge_width = edge_width @property def font_size(self) -> float | Literal["same as figure"]: return self._font_size @font_size.setter def font_size(self, font_size: float | Literal["same as figure"]) -> None: self._font_size = font_size @property def text_color(self) -> str: return self._text_color @text_color.setter def text_color(self, text_color: str) -> None: self._text_color = text_color @property def h_align(self) -> str: return self._h_align @h_align.setter def h_align(self, h_align: str) -> None: self._h_align = h_align @property def v_align(self) -> str: return self._v_align @v_align.setter def v_align(self, v_align: str) -> None: self._v_align = v_align @property def show_coordinates(self) -> bool: return self._show_coordinates @show_coordinates.setter def show_coordinates(self, show_coordinates: bool) -> None: self._show_coordinates = show_coordinates @property def coordinates(self) -> tuple[float, float]: return (self._x, self._y) @coordinates.setter def coordinates(self, coordinates: tuple[float, float]) -> None: self._x, self._y = coordinates
[docs] def copy(self) -> Self: """ Returns a deep copy of the :class:`~graphinglib.graph_elements.Point` object. """ return deepcopy(self)
[docs] def add_coordinates(self) -> None: """ Displays the coordinates of the :class:`~graphinglib.graph_elements.Point` next to it. """ self._show_coordinates = True
def _plot_element(self, axes: plt.Axes, z_order: int, **kwargs) -> None: """ Plots the element in the specified `Axes <https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.html>`_. """ if self._color is None and self._edge_color is None: raise GraphingException( "Both the face color and edge color of the point can't be None. Set at least one of them." ) size = self._font_size if self._font_size != "same as figure" else None prefix = " " if self._h_align == "left" else "" postfix = " " if self._h_align == "right" else "" if self._label is not None and not self._show_coordinates: point_label = prefix + self._label + postfix else: point_label = None params = { "c": self._color if self._color is not None else "none", "edgecolors": self._edge_color if self._edge_color is not None else "none", "s": self._marker_size, "marker": self._marker_style, "linewidths": self._edge_width, } params = {k: v for k, v in params.items() if v != "default"} axes.scatter( self._x, self._y, zorder=z_order, **params, ) # get text color. if _text_color is "same as point", use the color of the point (prioritize edge color, then face color) if self._text_color == "same as point": if self._edge_color is not None: text_color = self._edge_color else: text_color = self._color else: text_color = self._text_color params = { "color": text_color, "fontsize": size, "horizontalalignment": self._h_align, "verticalalignment": self._v_align, } params = {k: v for k, v in params.items() if v != "default"} axes.annotate( point_label, (self._x, self._y), zorder=z_order, **params, ) if self._show_coordinates: prefix = " " if self._h_align == "left" else "" postfix = " " if self._h_align == "right" else "" if self._label is not None: point_label = ( prefix + self._label + " : " + f"({self._x:.3f}, {self._y:.3f})" + postfix ) else: point_label = prefix + f"({self._x:.3f}, {self._y:.3f})" + postfix if self._text_color == "same as point": if self._edge_color is not None: text_color = self._edge_color else: text_color = self._color else: text_color = self._text_color params = { "color": text_color, "fontsize": size, "horizontalalignment": self._h_align, "verticalalignment": self._v_align, } params = {k: v for k, v in params.items() if v != "default"} axes.annotate( point_label, (self._x, self._y), zorder=z_order, **params, )
[docs] @dataclass class Text: """ This class allows text to be plotted. It is also possible to attach an arrow to the :class:`~graphinglib.graph_elements.Text` with the method :py:meth:`~graphinglib.graph_elements.Text.attach_arrow` to point at something of interest in the plot. Parameters ---------- x, y : float The x and y coordinates at which to plot the :class:`~graphinglib.graph_elements.Text`. text : str The text to be plotted. color : str Color of the text. Default depends on the ``figure_style`` configuration. font_size : float Font size of the text. Default depends on the ``figure_style`` configuration. h_align, v_align : str Horizontal and vertical alignment of the text. Default depends on the ``figure_style`` configuration. """ _x: float _y: float _text: str _color: str = "default" _font_size: float | Literal["same as figure"] = "same as figure" _h_align: str = "default" _v_align: str = "default" _arrow_pointing_to: Optional[tuple[float]] = field(default=None, init=False)
[docs] def __init__( self, x: float, y: float, text: str, color: str = "default", font_size: float | Literal["same as figure"] = "same as figure", h_align: str = "default", v_align: str = "default", ) -> None: """ This class allows text to be plotted. It is also possible to attach an arrow to the :class:`~graphinglib.graph_elements.Text` with the method :py:meth:`~graphinglib.graph_elements.Text.attach_arrow` to point at something of interest in the plot. Parameters ---------- x, y : float The x and y coordinates at which to plot the :class:`~graphinglib.graph_elements.Text`. text : str The text to be plotted. color : str Color of the text. Default depends on the ``figure_style`` configuration. font_size : float Font size of the text. Default depends on the ``figure_style`` configuration. h_align, v_align : str Horizontal and vertical alignment of the text. Default depends on the ``figure_style`` configuration. """ self._x = x self._y = y self._text = text self._color = color self._font_size = font_size self._h_align = h_align self._v_align = v_align self._arrow_pointing_to = None
@property def x(self) -> float: return self._x @x.setter def x(self, x: float) -> None: self._x = x @property def y(self) -> float: return self._y @y.setter def y(self, y: float) -> None: self._y = y @property def text(self) -> str: return self._text @text.setter def text(self, text: str) -> None: self._text = text @property def color(self) -> str: return self._color @color.setter def color(self, color: str) -> None: self._color = color @property def font_size(self) -> float | Literal["same as figure"]: return self._font_size @font_size.setter def font_size(self, font_size: float | Literal["same as figure"]) -> None: self._font_size = font_size @property def h_align(self) -> str: return self._h_align @h_align.setter def h_align(self, h_align: str) -> None: self._h_align = h_align @property def v_align(self) -> str: return self._v_align @v_align.setter def v_align(self, v_align: str) -> None: self._v_align = v_align @property def arrow_pointing_to(self) -> Optional[tuple[float]]: return self._arrow_pointing_to @arrow_pointing_to.setter def arrow_pointing_to(self, arrow_pointing_to: Optional[tuple[float]]) -> None: self._arrow_pointing_to = arrow_pointing_to
[docs] def copy(self) -> Self: """ Returns a deep copy of the :class:`~graphinglib.graph_elements.Text` object. """ return deepcopy(self)
[docs] def add_arrow( self, points_to: tuple[float, float], width: Optional[float] = None, shrink: Optional[float] = None, head_width: Optional[float] = None, head_length: Optional[float] = None, ) -> None: """ Adds an arrow pointing from the :class:`~graphinglib.graph_elements.Text` to a specified point. Parameters ---------- points_to: tuple[float, float] Coordinates at which to point. width : float, optional Arrow width. shrink : float, optional Fraction of the total length of the arrow to shrink from both ends. A value of 0.5 means the arrow is no longer visible. head_width : float, optional Width of the head of the arrow. head_length : float, optional Length of the head of the arrow. """ self._arrow_pointing_to = points_to self._arrow_properties = {} if width is not None: self._arrow_properties["width"] = width if shrink is not None: self._arrow_properties["shrink"] = shrink if head_width is not None: self._arrow_properties["headwidth"] = head_width if head_length is not None: self._arrow_properties["headlength"] = head_length
def _plot_element(self, axes: plt.Axes, z_order: int, **kwargs) -> None: """ Plots the element in the specified Axes """ size = self._font_size if self._font_size != "same as figure" else None params = { "color": self._color, "fontsize": size, "horizontalalignment": self._h_align, "verticalalignment": self._v_align, } params = {k: v for k, v in params.items() if v != "default"} axes.text( self._x, self._y, self._text, zorder=z_order, **params, ) if self._arrow_pointing_to is not None: self._arrow_properties["color"] = self._color params = { "color": self._color, "fontsize": size, "horizontalalignment": self._h_align, "verticalalignment": self._v_align, } params = {k: v for k, v in params.items() if v != "default"} if self._color != "default": self._arrow_properties["color"] = self._color params["arrowprops"] = self._arrow_properties axes.annotate( self._text, self._arrow_pointing_to, xytext=(self._x, self._y), zorder=z_order, **params, )
[docs] @dataclass class Table: """ This class allows to plot a table inside a Figure or MultiFigure. The Table object can be used to add raw data to a figure or add supplementary information like output parameters for a fit or anyother operation. Parameters ---------- cell_text : list[str] Text or data to be displayed in the table. The shape of the provided data determines the number of columns and rows. cell_colors : ArrayLike or str, optional Colors to apply to the cells' background. Must be a list of colors the same shape as the cells. Default depends on the ``figure_style`` configuration. cell_align : str Alignment of the cells' text. Must be one of the following: {'left', 'center', 'right'}. Default depends on the ``figure_style`` configuration. col_labels : list[str], optional List of labels for the rows of the table. If none are specified, no row labels are displayed. col_widths : list[float], optional Widths to apply to the columns. Must be a list the same length as the number of columns. col_align : str Alignment of the column labels' text. Must be one of the following: {'left', 'center', 'right'}. Default depends on the ``figure_style`` configuration. col_colors : ArrayLike or str, optional Colors to apply to the column labels' background. Must be a list of colors the same length as the number of columns. Default depends on the ``figure_style`` configuration. row_labels : list[str], optional List of labels for the rows of the table. If none are specified, no row labels are displayed. row_align : str Alignment of the row labels' text. Must be one of the following: {'left', 'center', 'right'}. Default depends on the ``figure_style`` configuration. row_colors : ArrayLike or str, optional Colors to apply to the row labels' background. Must be a list of colors the same length as the number of rows. Default depends on the ``figure_style`` configuration. edge_width : float or str, optional Width of the table's edges. Default depends on the ``figure_style`` configuration. edge_color : str, optional Color of the table's edges. Default depends on the ``figure_style`` configuration. text_color : str, optional Color of the text in the table. Default depends on the ``figure_style`` configuration. scaling : tuple[float], optional Horizontal and vertical scaling factors to apply to the table. Defaults to ``(1, 1.5)``. location : str Position of the table inside the axes. Must be one of the following: {'best', 'bottom', 'bottom left', 'bottom right', 'center', 'center left', 'center right', 'left', 'lower center', 'lower left', 'lower right', 'right', 'top', 'top left', 'top right', 'upper center', 'upper left', 'upper right'} Defaults to ``"best"``. """
[docs] def __init__( self, cell_text: list[str], cell_colors: ArrayLike | str = "default", cell_align: str = "default", col_labels: Optional[list[str]] = None, col_widths: Optional[list[float]] = None, col_align: str = "default", col_colors: ArrayLike | str = "default", row_labels: Optional[list[str]] = None, row_align: str = "default", row_colors: ArrayLike | str = "default", edge_width: float | Literal["default"] = "default", edge_color: str = "default", text_color: str = "default", scaling: tuple[float, float] = (1.0, 1.5), location: str = "best", ) -> None: """ This class allows to plot a table inside a Figure or MultiFigure. The Table object can be used to add raw data to a figure or add supplementary information like output parameters for a fit or anyother operation. Parameters ---------- cell_text : list[str] Text or data to be displayed in the table. The shape of the provided data determines the number of columns and rows. cell_colors : ArrayLike or str, optional Colors to apply to the cells' background. Must be a list of colors the same shape as the cells. Default depends on the ``figure_style`` configuration. cell_align : str Alignment of the cells' text. Must be one of the following: {'left', 'center', 'right'}. Default depends on the ``figure_style`` configuration. col_labels : list[str], optional List of labels for the rows of the table. If none are specified, no row labels are displayed. col_widths : list[float], optional Widths to apply to the columns. Must be a list the same length as the number of columns. col_align : str Alignment of the column labels' text. Must be one of the following: {'left', 'center', 'right'}. Default depends on the ``figure_style`` configuration. col_colors : ArrayLike or str, optional Colors to apply to the column labels' background. Must be a list of colors the same length as the number of columns. Default depends on the ``figure_style`` configuration row_labels : list[str], optional List of labels for the rows of the table. If none are specified, no row labels are displayed. row_align : str Alignment of the row labels' text. Must be one of the following: {'left', 'center', 'right'}. Default depends on the ``figure_style`` configuration. row_colors : ArrayLike or str, optional Colors to apply to the row labels' background. Must be a list of colors the same length as the number of rows. Default depends on the ``figure_style`` configuration. edge_width : float or str, optional Width of the table's edges. Default depends on the ``figure_style`` configuration. edge_color : str, optional Color of the table's edges. Default depends on the ``figure_style`` configuration. text_color : str, optional Color of the text within the table. Default depends on the ``figure_style`` configuration. scaling : tuple[float], optional Horizontal and vertical scaling factors to apply to the table. Defaults to ``(1, 1.5)``. location : str Position of the table inside the axes. Must be one of the following: {'best', 'bottom', 'bottom left', 'bottom right', 'center', 'center left', 'center right', 'left', 'lower center', 'lower left', 'lower right', 'right', 'top', 'top left', 'top right', 'upper center', 'upper left', 'upper right'} Defaults to ``"best"``. """ self._cell_text = cell_text self._cell_colors = cell_colors self._cell_align = cell_align self._col_labels = col_labels self._col_widths = col_widths self._col_align = col_align self._col_colors = col_colors self._row_labels = row_labels self._row_align = row_align self._row_colors = row_colors self._edge_width = edge_width self._edge_color = edge_color self._text_color = text_color self._scaling = scaling self._location = location
@property def cell_text(self) -> list[str]: return self._cell_text @cell_text.setter def cell_text(self, cell_text: list[str]) -> None: self._cell_text = cell_text @property def cell_colors(self) -> ArrayLike | str: return self._cell_colors @cell_colors.setter def cell_colors(self, cell_colors: list) -> None: self._cell_colors = cell_colors @property def cell_align(self) -> str: return self._cell_align @cell_align.setter def cell_align(self, cell_align: str) -> None: self._cell_align = cell_align @property def col_labels(self) -> list[str]: return self._col_labels @col_labels.setter def col_labels(self, col_labels: list[str]) -> None: self._col_labels = col_labels @property def col_widths(self) -> list[float]: return self._col_widths @col_widths.setter def col_widths(self, col_widths: list[float]) -> None: self._col_widths = col_widths @property def col_align(self) -> str: return self._col_align @col_align.setter def col_align(self, col_align: str) -> None: self._col_align = col_align @property def col_colors(self) -> ArrayLike | str: return self._col_colors @col_colors.setter def col_colors(self, col_colors: list) -> None: self._col_colors = col_colors @property def row_labels(self) -> list[str]: return self._row_labels @row_labels.setter def row_labels(self, row_labels: list[str]) -> None: self._row_labels = row_labels @property def row_align(self) -> str: return self._row_align @row_align.setter def row_align(self, row_align: str) -> None: self._row_align = row_align @property def row_colors(self) -> ArrayLike | str: return self._row_colors @row_colors.setter def row_colors(self, row_colors: list) -> None: self._row_colors = row_colors @property def edge_width(self) -> float: return self._edge_width @edge_width.setter def edge_width(self, edge_width: float) -> None: self._edge_width = edge_width for (i, j), cell in self.handle.get_celld().items(): cell.set_linewidth(self._edge_width) @property def edge_color(self) -> str: return self._edge_color @edge_color.setter def edge_color(self, edge_color: str) -> None: self._edge_color = edge_color for (i, j), cell in self.handle.get_celld().items(): cell.set_edgecolor(self._edge_color) @property def text_color(self) -> str: return self._text_color @text_color.setter def text_color(self, text_color: str) -> None: self._text_color = text_color for (i, j), cell in self.handle.get_celld().items(): cell.set_text_props(color=self._text_color) @property def scaling(self) -> tuple[float]: return self._scaling @scaling.setter def scaling(self, scaling: tuple[float]) -> None: self._scaling = scaling @property def location(self) -> str: return self._location @location.setter def location(self, location: str) -> None: self._location = location
[docs] def copy(self) -> Self: """ Returns a deep copy of the :class:`~graphinglib.graph_elements.Table` object. """ return deepcopy(self)
def _plot_element(self, axes: plt.Axes, z_order: int, **kwargs) -> None: """ Plots the element in the specified `Axes <https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.html>`_. """ params = { "cellLoc": self._cell_align, "colLoc": self._col_align, "rowLoc": self._row_align, } params = {k: v for k, v in params.items() if v != "default"} # Set colors to correct shape if they are strings if isinstance(self._cell_colors, str): self._cell_colors = [[self._cell_colors] * len(self._cell_text[0])] * len( self._cell_text ) if isinstance(self._col_colors, str): self._col_colors = [self._col_colors] * len(self._cell_text[0]) if isinstance(self._row_colors, str): self._row_colors = [self._row_colors] * len(self._cell_text) self.handle = axes.table( cellText=self._cell_text, cellColours=self._cell_colors, colLabels=self._col_labels, colWidths=self._col_widths, colColours=self._col_colors, rowLabels=self._row_labels, rowColours=self._row_colors, loc=self._location, zorder=z_order, **params, ) self.handle.auto_set_font_size(False) self.handle.scale(self._scaling[0], self._scaling[1]) for (i, j), cell in self.handle.get_celld().items(): cell.set_text_props(color=self._text_color) cell.set_edgecolor(self._edge_color) cell.set_linewidth(self._edge_width)