Source code for modelly.viz.render.drawers.orthogonal

"""Drawer for orthogonal grid spaces."""

import altair as alt
import numpy as np
import pandas as pd

from modelly.viz.render.drawers.base import (
    MARKER_SPAN_POINTS,
    BaseSpaceDrawer,
    OrthogonalGrid,
    axes_with_figure_kwargs,
    chart_properties,
)

# Cell centres sit on integers, so cell edges are half a unit away.
HALF_CELL = 0.5


[docs] class OrthogonalSpaceDrawer(BaseSpaceDrawer): """Drawer for orthogonal grid spaces (SingleGrid, MultiGrid, Moore, VonNeumann).""" def __init__(self, space: OrthogonalGrid): """Initialize the orthogonal space drawer. Args: space: The orthogonal grid space to draw """ super().__init__(space) self.s_default = ( MARKER_SPAN_POINTS / max(self.space.width, self.space.height) ) ** 2 # Parameters for visualization limits self.viz_xmin = -HALF_CELL self.viz_xmax = self.space.width - HALF_CELL self.viz_ymin = -HALF_CELL self.viz_ymax = self.space.height - HALF_CELL
[docs] def draw_matplotlib(self, ax=None, **draw_space_kwargs): """Draw the orthogonal grid using matplotlib. Args: ax: Matplotlib axes object to draw on **draw_space_kwargs: Additional keyword arguments for styling. Examples: figsize=(10, 10), color="blue", linewidth=2. Returns: The modified axes object """ ax = axes_with_figure_kwargs(ax, draw_space_kwargs) # gridline styling kwargs line_kwargs = { "color": "gray", "linestyle": ":", "linewidth": 1, "alpha": 1, } line_kwargs.update(draw_space_kwargs) ax.set_xlim(self.viz_xmin, self.viz_xmax) ax.set_ylim(self.viz_ymin, self.viz_ymax) # Draw grid lines for x in np.arange(-HALF_CELL, self.space.width, 1): ax.axvline(x, **line_kwargs) for y in np.arange(-HALF_CELL, self.space.height, 1): ax.axhline(y, **line_kwargs) return ax
[docs] def draw_altair(self, chart_width=450, chart_height=350, **draw_chart_kwargs): """Draw the orthogonal grid using Altair. Args: chart_width: Width for the shown chart chart_height: Height for the shown chart **draw_chart_kwargs: Additional keyword arguments for styling the chart. Examples: width=500, height=500, title="Grid". Returns: Altair chart object """ # for axis and grid styling axis_kwargs = { "xlabel": draw_chart_kwargs.pop("xlabel", "X"), "ylabel": draw_chart_kwargs.pop("ylabel", "Y"), "grid_color": draw_chart_kwargs.pop("grid_color", "lightgray"), "grid_dash": draw_chart_kwargs.pop("grid_dash", [2, 2]), "grid_width": draw_chart_kwargs.pop("grid_width", 1), "grid_opacity": draw_chart_kwargs.pop("grid_opacity", 1), } chart_props = chart_properties(chart_width, chart_height, draw_chart_kwargs) x_domain = [self.viz_xmin, self.viz_xmax] y_domain = [self.viz_ymin, self.viz_ymax] return ( alt.Chart(pd.DataFrame([{}])) .mark_point(opacity=0) .encode( x=alt.X( "X:Q", **_gridded_axis(axis_kwargs["xlabel"], x_domain, axis_kwargs) ), y=alt.Y( "Y:Q", **_gridded_axis(axis_kwargs["ylabel"], y_domain, axis_kwargs) ), ) .properties(**chart_props) )
def _gridded_axis(title, domain, axis_kwargs): """Return the title, scale and gridded axis for one Altair position channel.""" return { "title": title, "scale": alt.Scale(domain=domain, nice=False), "axis": alt.Axis( grid=True, gridColor=axis_kwargs["grid_color"], gridDash=axis_kwargs["grid_dash"], gridWidth=axis_kwargs["grid_width"], gridOpacity=axis_kwargs["grid_opacity"], ), }