Skip to content

styling

styling

Grid pydantic-model

Bases: HashableBase

Container for major and minor grid line configuration.

Attributes:

Name Type Description
major GridAxis

Configuration for major grid lines.

minor GridAxis

Configuration for minor grid lines.

enable_minor_ticks bool

Whether to enable minor ticks on the axes.

Show JSON schema:
{
  "$defs": {
    "GridAxis": {
      "additionalProperties": false,
      "description": "Controls styling and visibility for one type of grid (major or minor).\n\nAttributes:\n    show (bool): Whether to display this grid axis.\n    pen (Pen): Style and label information for drawing to matplotlib axes.",
      "properties": {
        "show": {
          "default": false,
          "title": "Show",
          "type": "boolean"
        },
        "pen": {
          "$ref": "#/$defs/Pen",
          "default": {
            "color": "gray",
            "size": 0.75,
            "alpha": 1.0,
            "zorder": 0.0,
            "linestyle": "-",
            "label": null
          }
        }
      },
      "title": "GridAxis",
      "type": "object"
    },
    "Pen": {
      "additionalProperties": false,
      "description": "Defines the pen drawing to matplotlib.\n\nAttributes:\n    color (str): Color of line\n    size (float): Line width\n    alpha (float): Opacity from 0 to 1 (inclusive)\n    linestyle (Union[str, Tuple[int, Tuple[int, ...]]]): Linestyle to plot. Supports `str` or `tuple` definition ([matplotlib documentation](https://matplotlib.org/stable/gallery/lines_bars_and_markers/linestyles.html)).\n    zorder (float): Prioritization\n    label (Union[str, None]): Legend label",
      "properties": {
        "color": {
          "anyOf": [
            {
              "maxItems": 3,
              "minItems": 3,
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "type": "array"
            },
            {
              "maxItems": 4,
              "minItems": 4,
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "type": "array"
            },
            {
              "type": "string"
            }
          ],
          "default": "k",
          "title": "Color"
        },
        "size": {
          "default": 1,
          "title": "Size",
          "type": "number"
        },
        "alpha": {
          "default": 1,
          "title": "Alpha",
          "type": "number"
        },
        "zorder": {
          "default": 0,
          "title": "Zorder",
          "type": "number"
        },
        "linestyle": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "maxItems": 2,
              "minItems": 2,
              "prefixItems": [
                {
                  "type": "integer"
                },
                {
                  "items": {
                    "type": "integer"
                  },
                  "type": "array"
                }
              ],
              "type": "array"
            }
          ],
          "default": "-",
          "title": "Linestyle"
        },
        "label": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Label"
        }
      },
      "title": "Pen",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Container for major and minor grid line configuration.\n\nAttributes:\n    major (GridAxis): Configuration for major grid lines.\n    minor (GridAxis): Configuration for minor grid lines.\n    enable_minor_ticks (bool): Whether to enable minor ticks on the axes.",
  "properties": {
    "major": {
      "$ref": "#/$defs/GridAxis",
      "default": {
        "show": false,
        "pen": {
          "alpha": 1.0,
          "color": "gray",
          "label": null,
          "linestyle": "-",
          "size": 0.75,
          "zorder": 0.0
        }
      }
    },
    "minor": {
      "$ref": "#/$defs/GridAxis",
      "default": {
        "show": false,
        "pen": {
          "alpha": 1.0,
          "color": "gray",
          "label": null,
          "linestyle": "-",
          "size": 0.75,
          "zorder": 0.0
        }
      }
    },
    "enable_minor_ticks": {
      "default": false,
      "title": "Enable Minor Ticks",
      "type": "boolean"
    },
    "zorder": {
      "default": -1,
      "title": "Zorder",
      "type": "number"
    }
  },
  "title": "Grid",
  "type": "object"
}

Config:

  • extra: 'forbid'

Fields:

from_theme classmethod

from_theme(name: GridTheme) -> Grid

Predefined themes for common grid styles.

Source code in src/trendify/api/styling/grid.py
@classmethod
def from_theme(cls, name: GridTheme) -> Grid:
    """
    Predefined themes for common grid styles.
    """
    themes = {
        GridTheme.MATLAB: cls(
            major=GridAxis(
                show=True,
                pen=Pen(
                    color="#b0b0b0",
                    linestyle="-",
                    size=0.8,
                    alpha=0.35,
                    label=None,
                ),
            ),
            minor=GridAxis(
                show=True,
                pen=Pen(
                    color="#b0b0b0",
                    linestyle=(0, (3, 1, 1, 1)),
                    size=0.6,
                    alpha=0.25,
                    label=None,
                ),
            ),
            enable_minor_ticks=True,
        ),
        GridTheme.LIGHT: cls(
            major=GridAxis(
                show=True,
                pen=Pen(
                    color="#E0E0E0",
                    linestyle="--",
                    size=0.7,
                    alpha=0.9,
                    label=None,
                ),
            ),
            minor=GridAxis(show=False),
            enable_minor_ticks=False,
        ),
        GridTheme.DARK: cls(
            major=GridAxis(
                show=True,
                pen=Pen(
                    color="#444444",
                    linestyle="--",
                    size=0.7,
                    alpha=0.5,
                    label=None,
                ),
            ),
            minor=GridAxis(show=False),
            enable_minor_ticks=False,
        ),
    }

    try:
        return themes[name]
    except KeyError:
        raise ValueError(f"Unknown grid theme: {name!r}")

union_from_iterable classmethod

union_from_iterable(grids: Iterable[Grid]) -> Grid

Gets the most inclusive grid format from a list of Grid objects. Requires that all GridAxis fields (major/minor) are consistent across the objects.

Source code in src/trendify/api/styling/grid.py
@classmethod
def union_from_iterable(cls, grids: Iterable[Grid]) -> Grid:
    """
    Gets the most inclusive grid format from a list of Grid objects.
    Requires that all GridAxis fields (major/minor) are consistent across the objects.
    """
    grids = list(set(grids) - {None})
    if not grids:
        return cls()

    # Enforce consistent GridAxis settings
    [major] = set(g.major for g in grids)
    [minor] = set(g.minor for g in grids)
    [enable_minor_ticks] = set(g.enable_minor_ticks for g in grids)
    [zorder] = set(g.zorder for g in grids)

    return cls(
        major=major,
        minor=minor,
        enable_minor_ticks=enable_minor_ticks,
        zorder=zorder,
    )

GridAxis pydantic-model

Bases: HashableBase

Controls styling and visibility for one type of grid (major or minor).

Attributes:

Name Type Description
show bool

Whether to display this grid axis.

pen Pen

Style and label information for drawing to matplotlib axes.

Show JSON schema:
{
  "$defs": {
    "Pen": {
      "additionalProperties": false,
      "description": "Defines the pen drawing to matplotlib.\n\nAttributes:\n    color (str): Color of line\n    size (float): Line width\n    alpha (float): Opacity from 0 to 1 (inclusive)\n    linestyle (Union[str, Tuple[int, Tuple[int, ...]]]): Linestyle to plot. Supports `str` or `tuple` definition ([matplotlib documentation](https://matplotlib.org/stable/gallery/lines_bars_and_markers/linestyles.html)).\n    zorder (float): Prioritization\n    label (Union[str, None]): Legend label",
      "properties": {
        "color": {
          "anyOf": [
            {
              "maxItems": 3,
              "minItems": 3,
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "type": "array"
            },
            {
              "maxItems": 4,
              "minItems": 4,
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "type": "array"
            },
            {
              "type": "string"
            }
          ],
          "default": "k",
          "title": "Color"
        },
        "size": {
          "default": 1,
          "title": "Size",
          "type": "number"
        },
        "alpha": {
          "default": 1,
          "title": "Alpha",
          "type": "number"
        },
        "zorder": {
          "default": 0,
          "title": "Zorder",
          "type": "number"
        },
        "linestyle": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "maxItems": 2,
              "minItems": 2,
              "prefixItems": [
                {
                  "type": "integer"
                },
                {
                  "items": {
                    "type": "integer"
                  },
                  "type": "array"
                }
              ],
              "type": "array"
            }
          ],
          "default": "-",
          "title": "Linestyle"
        },
        "label": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Label"
        }
      },
      "title": "Pen",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Controls styling and visibility for one type of grid (major or minor).\n\nAttributes:\n    show (bool): Whether to display this grid axis.\n    pen (Pen): Style and label information for drawing to matplotlib axes.",
  "properties": {
    "show": {
      "default": false,
      "title": "Show",
      "type": "boolean"
    },
    "pen": {
      "$ref": "#/$defs/Pen",
      "default": {
        "color": "gray",
        "size": 0.75,
        "alpha": 1.0,
        "zorder": 0.0,
        "linestyle": "-",
        "label": null
      }
    }
  },
  "title": "GridAxis",
  "type": "object"
}

Config:

  • extra: 'forbid'

Fields:

Legend pydantic-model

Bases: HashableBase

Configuration container for Matplotlib legend styling and placement.

The Legend class controls the appearance and position of the plot legend. Placement is governed by a combination of the loc and bbox_to_anchor parameters, mirroring Matplotlib's Axes.legend().

Attributes:

Name Type Description
visible bool

Whether the legend should be displayed. Defaults to True.

title str | None

Title displayed above the legend entries.

framealpha float

Opacity of the legend background. 1 = fully opaque, 0 = fully transparent.

loc LegendLocation

Anchor point for the legend (e.g., upper right, lower left). See LegendLocation enum for options.

ncol int

Number of columns to arrange legend entries into.

fancybox bool

Whether to draw a rounded (True) or square (False) legend frame.

edgecolor str

Color of the legend frame border. Default is "black".

bbox_to_anchor tuple[float, float] | None

Offset position of the legend in figure or axes coordinates. If None, the legend is placed inside the axes using loc.

Good starter values for common placements:

  • Inside (default):
    bbox_to_anchor=None
    
  • Outside right:
    loc=LegendLocation.CENTER_LEFT
    bbox_to_anchor=(1.02, 0.5)
    
  • Outside left:
    loc=LegendLocation.CENTER_RIGHT
    bbox_to_anchor=(-0.02, 0.5)
    
  • Outside top:
    loc=LegendLocation.LOWER_CENTER
    bbox_to_anchor=(0.5, 1.02)
    
  • Outside bottom:
    loc=LegendLocation.UPPER_CENTER
    bbox_to_anchor=(0.5, -0.02)
    
Show JSON schema:
{
  "$defs": {
    "LegendLocation": {
      "enum": [
        "best",
        "upper right",
        "upper left",
        "lower left",
        "lower right",
        "right",
        "center left",
        "center right",
        "lower center",
        "upper center",
        "center"
      ],
      "title": "LegendLocation",
      "type": "string"
    }
  },
  "description": "Configuration container for Matplotlib legend styling and placement.\n\nThe `Legend` class controls the appearance and position of the plot legend.\nPlacement is governed by a combination of the `loc` and `bbox_to_anchor`\nparameters, mirroring Matplotlib's `Axes.legend()`.\n\nAttributes:\n    visible (bool): Whether the legend should be displayed. Defaults to True.\n    title (str | None): Title displayed above the legend entries.\n    framealpha (float): Opacity of the legend background. 1 = fully opaque, 0 = fully transparent.\n    loc (LegendLocation): Anchor point for the legend (e.g., upper right, lower left). See `LegendLocation` enum for options.\n    ncol (int): Number of columns to arrange legend entries into.\n    fancybox (bool): Whether to draw a rounded (True) or square (False) legend frame.\n    edgecolor (str): Color of the legend frame border. Default is \"black\".\n    bbox_to_anchor (tuple[float, float] | None): Offset position of the legend in figure or axes coordinates. If None, the legend is placed inside the axes using `loc`.\n\n        Good starter values for common placements:\n\n        - **Inside (default)**:\n            ```python\n            bbox_to_anchor=None\n            ```\n        - **Outside right**:\n            ```python\n            loc=LegendLocation.CENTER_LEFT\n            bbox_to_anchor=(1.02, 0.5)\n            ```\n        - **Outside left**:\n            ```python\n            loc=LegendLocation.CENTER_RIGHT\n            bbox_to_anchor=(-0.02, 0.5)\n            ```\n        - **Outside top**:\n            ```python\n            loc=LegendLocation.LOWER_CENTER\n            bbox_to_anchor=(0.5, 1.02)\n            ```\n        - **Outside bottom**:\n            ```python\n            loc=LegendLocation.UPPER_CENTER\n            bbox_to_anchor=(0.5, -0.02)\n            ```",
  "properties": {
    "visible": {
      "default": true,
      "title": "Visible",
      "type": "boolean"
    },
    "title": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Title"
    },
    "framealpha": {
      "default": 1,
      "title": "Framealpha",
      "type": "number"
    },
    "loc": {
      "$ref": "#/$defs/LegendLocation",
      "default": "best"
    },
    "ncol": {
      "default": 1,
      "title": "Ncol",
      "type": "integer"
    },
    "fancybox": {
      "default": true,
      "title": "Fancybox",
      "type": "boolean"
    },
    "edgecolor": {
      "default": "black",
      "title": "Edgecolor",
      "type": "string"
    },
    "zorder": {
      "default": 10,
      "title": "Zorder",
      "type": "integer"
    },
    "bbox_to_anchor": {
      "anyOf": [
        {
          "maxItems": 2,
          "minItems": 2,
          "prefixItems": [
            {
              "type": "number"
            },
            {
              "type": "number"
            }
          ],
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Bbox To Anchor"
    }
  },
  "title": "Legend",
  "type": "object"
}

Fields:

plotly_location pydantic-field

plotly_location: dict

Convert matplotlib legend location to Plotly legend position parameters.

Returns:

Name Type Description
dict dict

Dictionary containing Plotly legend position parameters (x, y, xanchor, yanchor)

Marker pydantic-model

Bases: HashableBase

Defines marker for scattering to matplotlib

Attributes:

Name Type Description
color str

Color of line

size float

Line width

alpha float

Opacity from 0 to 1 (inclusive)

zorder float

Prioritization

label Union[str, None]

Legend label

symbol str

Matplotlib symbol string

Show JSON schema:
{
  "additionalProperties": false,
  "description": "Defines marker for scattering to matplotlib\n\nAttributes:\n    color (str): Color of line\n    size (float): Line width\n    alpha (float): Opacity from 0 to 1 (inclusive)\n    zorder (float): Prioritization\n    label (Union[str, None]): Legend label\n    symbol (str): Matplotlib symbol string",
  "properties": {
    "color": {
      "default": "k",
      "title": "Color",
      "type": "string"
    },
    "size": {
      "default": 5,
      "title": "Size",
      "type": "number"
    },
    "alpha": {
      "default": 1,
      "title": "Alpha",
      "type": "number"
    },
    "zorder": {
      "default": 0,
      "title": "Zorder",
      "type": "number"
    },
    "label": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Label"
    },
    "symbol": {
      "default": ".",
      "title": "Symbol",
      "type": "string"
    }
  },
  "title": "Marker",
  "type": "object"
}

Config:

  • extra: 'forbid'

Fields:

plotly_symbol pydantic-field

plotly_symbol: str

Convert matplotlib marker symbol to plotly symbol

rgba pydantic-field

rgba: str

Convert the pen's color to rgba string format.

Returns:

Name Type Description
str str

Color in 'rgba(r,g,b,a)' format where r,g,b are 0-255 and a is 0-1

as_scatter_plot_kwargs

as_scatter_plot_kwargs()

Returns:

Type Description
dict

dictionary of kwargs for matplotlib scatter

Source code in src/trendify/api/styling/marker.py
def as_scatter_plot_kwargs(self):
    """
    Returns:
        (dict): dictionary of `kwargs` for [matplotlib scatter][matplotlib.axes.Axes.scatter]
    """
    return {
        "marker": self.symbol,
        "c": self.color,
        "s": self.size,
        "alpha": self.alpha,
        "zorder": self.zorder,
        "label": self.label,
        "marker": self.symbol,
    }

from_pen classmethod

from_pen(pen: Pen, symbol: str = '.')

Converts Pen to marker with the option to specify a symbol

Source code in src/trendify/api/styling/marker.py
@classmethod
def from_pen(
    cls,
    pen: Pen,
    symbol: str = ".",
):
    """
    Converts Pen to marker with the option to specify a symbol
    """
    return cls(symbol=symbol, **pen.model_dump().pop("linestyle"))

get_contrast_color

get_contrast_color(background_luminance: float = 1.0) -> str

Returns 'white' or 'black' to provide the best contrast against the pen's color, taking into account the alpha (transparency) value of the line.

Parameters:

Name Type Description Default
background_luminance float

The luminance of the background (default is 1.0 for white).

1.0

Returns:

Name Type Description
str str

'white' or 'black'

Source code in src/trendify/api/styling/marker.py
def get_contrast_color(self, background_luminance: float = 1.0) -> str:
    """
    Returns 'white' or 'black' to provide the best contrast against the pen's color,
    taking into account the alpha (transparency) value of the line.

    Args:
        background_luminance (float): The luminance of the background (default is 1.0 for white).

    Returns:
        str: 'white' or 'black'
    """
    # Convert the pen's color to RGB (0-255 range) and get alpha
    if isinstance(self.color, tuple):
        if len(self.color) == 3:  # RGB tuple
            r, g, b = self.color
            a = self.alpha
        else:  # RGBA tuple
            r, g, b, a = self.color
        r, g, b = int(r * 255), int(g * 255), int(b * 255)
    else:  # String color (name or hex)
        rgba_vals = to_rgba(self.color, self.alpha)
        r, g, b = [int(x * 255) for x in rgba_vals[:3]]
        a = rgba_vals[3]

    # Calculate relative luminance of the pen's color
    def luminance(channel):
        channel /= 255.0
        return (
            channel / 12.92
            if channel <= 0.03928
            else ((channel + 0.055) / 1.055) ** 2.4
        )

    color_luminance = (
        0.2126 * luminance(r) + 0.7152 * luminance(g) + 0.0722 * luminance(b)
    )

    # Blend the color luminance with the background luminance based on alpha
    blended_luminance = (1 - a) * background_luminance + a * color_luminance

    # Return white for dark blended colors, black for light blended colors
    return "white" if blended_luminance < 0.5 else "black"