from dataclasses import dataclass
from datetime import date, datetime
from typing import Literal
from plotly import graph_objects as go
from visualization_toolkit.helpers.plotly.colors import resolve_color
from visualization_toolkit.helpers.plotly.theme import (
SHADE_OPACITY,
SHADE_LINE_WIDTH,
COLORS,
)
@dataclass
class BaseShadingMixin:
start: int | float | date | datetime
end: int | float | date | datetime
color: str = COLORS["light-grey"][400]
def __post_init__(self):
if self.start >= self.end:
raise ValueError("start must be less than the end value")
@property
def resolved_color(self):
return resolve_color(self.color)
@dataclass
class ShadeX(BaseShadingMixin):
"""
Add a shaded rectangle region that spans vertically on the chart
between the ``start`` and ``end`` values on the x-axis.
:param start: The starting value where the shaded region begins on the x-axis.
:param end: The ending value where the shaded region ends on the x-axis.
:param color: Fill color of the shaded region. Defaults to light-grey.
Examples
^^^^^^^^^^^^^
.. code-block:: python
:caption: Example of creating a chart with shaded vertical areas. Note that the start and end values correspond to the x-axis.
from visualization_toolkit.helpers.plotly import chart, axis, series, annotation, shade_x
fig = chart(
df,
x_axis=axis(
column_name="year",
label="Year",
),
chart_series=[
series(
column_name="lifeExp",
category_column_name="country",
location="y1",
),
],
y1_axis=axis(
label="Life Expectancy",
axis_type="number",
),
shaded_regions=[
shade_x(start=1950, end=1955, color="green"),
shade_x(start=1970, end=1975, color="red"),
],
)
display(fig)
"""
def add_to_figure(self, fig: go.Figure):
fig.add_vrect(
x0=self.start,
x1=self.end,
fillcolor=self.resolved_color,
opacity=SHADE_OPACITY,
layer="below",
line_width=SHADE_LINE_WIDTH,
)
@dataclass
class ShadeY(BaseShadingMixin):
"""
Add a shaded rectangle region that spans horizontally on the chart
between the ``start`` and ``end`` values on the y-axis.
:param start: The starting value where the shaded region begins on the y-axis.
:param end: The ending value where the shaded region ends on the y-axis.
:param color: Fill color of the shaded region. Defaults to light-grey.
Examples
^^^^^^^^^^^^^
.. code-block:: python
:caption: Example of creating a chart with shaded horizontal areas. Note that the start and end values correspond to the y-axis.
from visualization_toolkit.helpers.plotly import chart, axis, series, annotation, shade_y
fig = chart(
df,
x_axis=axis(
column_name="year",
label="Year",
),
chart_series=[
series(
column_name="lifeExp",
category_column_name="country",
location="y1",
),
],
y1_axis=axis(
label="Life Expectancy",
axis_type="number",
),
shaded_regions=[
shade_y(start=50, end=55, color="green"),
shade_y(start=70, end=75, color="red"),
],
)
display(fig)
"""
location: Literal["y1", "y2"] = "y1"
def add_to_figure(self, fig: go.Figure):
fig.add_hrect(
y0=self.start,
y1=self.end,
fillcolor=self.resolved_color,
opacity=SHADE_OPACITY,
layer="below",
line_width=SHADE_LINE_WIDTH,
secondary_y=self.location == "y2",
)