Source code for simstack.models.charts_artifact

from typing import List, Union, Literal, Optional, Dict, Any

from odmantic import Model, Field, EmbeddedModel, ObjectId

from simstack.models import simstack_model


# Chart Series Definitions
[docs] class AGChartSeriesBase(EmbeddedModel): """Base class for AG-Charts series configuration.""" type: str = Field(..., description="Chart series type") xKey: str = Field(..., description="Key for x-axis data") yKey: str = Field(..., description="Key for y-axis data") visible: Optional[bool] = Field( default=True, description="Whether series is visible" ) showInLegend: Optional[bool] = Field(default=True, description="Show in legend") title: Optional[str] = Field(default=None, description="Series title") # Chart data data: List[Dict[str, Any]] = Field(default_factory=list, description="Chart data")
[docs] class AGLineSeriesConfig(AGChartSeriesBase): """AG-Charts line series configuration.""" type: Literal["line"] = "line" strokeWidth: Optional[float] = Field(default=2, description="Line stroke width") strokeOpacity: Optional[float] = Field(default=1, description="Line stroke opacity") lineDash: Optional[List[float]] = Field( default=None, description="Line dash pattern" ) marker: Optional[Dict[str, Any]] = Field( default=None, description="Marker configuration" ) tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGBarSeriesConfig(AGChartSeriesBase): """AG-Charts bar series configuration.""" type: Literal["bar"] = "bar" fillOpacity: Optional[float] = Field(default=1, description="Bar fill opacity") strokeWidth: Optional[float] = Field(default=0, description="Bar stroke width") cornerRadius: Optional[float] = Field(default=0, description="Bar corner radius") tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGRangeBarSeriesConfig(EmbeddedModel): """AG-Charts range-bar series configuration.""" type: Literal["range-bar"] = "range-bar" xKey: str = Field(..., description="Key for x-axis data") yLowKey: str = Field(..., description="Key for low range value") yHighKey: str = Field(..., description="Key for high range value") xName: Optional[str] = Field(default=None, description="X axis display name") yName: Optional[str] = Field(default=None, description="Y axis display name") yLowName: Optional[str] = Field(default=None, description="Low value display name") yHighName: Optional[str] = Field(default=None, description="High value display name") direction: Optional[Literal["horizontal", "vertical"]] = Field( default=None, description="Bar rendering direction" ) visible: Optional[bool] = Field( default=True, description="Whether series is visible" ) showInLegend: Optional[bool] = Field(default=True, description="Show in legend") title: Optional[str] = Field(default=None, description="Series title") data: List[Dict[str, Any]] = Field(default_factory=list, description="Chart data") fillOpacity: Optional[float] = Field(default=1, description="Bar fill opacity") strokeWidth: Optional[float] = Field(default=0, description="Bar stroke width") cornerRadius: Optional[float] = Field(default=0, description="Bar corner radius") tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGColumnSeriesConfig(AGChartSeriesBase): """AG-Charts column series configuration.""" type: Literal["column"] = "column" fillOpacity: Optional[float] = Field(default=1, description="Column fill opacity") strokeWidth: Optional[float] = Field(default=0, description="Column stroke width") cornerRadius: Optional[float] = Field(default=0, description="Column corner radius") tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGAreaSeriesConfig(AGChartSeriesBase): """AG-Charts area series configuration.""" type: Literal["area"] = "area" fillOpacity: Optional[float] = Field(default=0.8, description="Area fill opacity") strokeWidth: Optional[float] = Field(default=2, description="Area stroke width") marker: Optional[Dict[str, Any]] = Field( default=None, description="Marker configuration" ) tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGScatterSeriesConfig(AGChartSeriesBase): """AG-Charts scatter series configuration.""" type: Literal["scatter"] = "scatter" marker: Optional[Dict[str, Any]] = Field( default=None, description="Marker configuration" ) tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGHeatmapSeriesConfig(AGChartSeriesBase): """AG-Charts heatmap series configuration.""" type: Literal["heatmap"] = "heatmap" colorKey: str = Field(..., description="Key for heatmap color values") xName: Optional[str] = Field(default=None, description="X axis display name") yName: Optional[str] = Field(default=None, description="Y axis display name") colorName: Optional[str] = Field(default=None, description="Color value display name") colorRange: Optional[List[str]] = Field( default=None, description="Color interpolation range" ) colorDomain: Optional[List[float]] = Field( default=None, description="Color domain [min, max]" ) stroke: Optional[str] = Field(default=None, description="Cell border color") strokeWidth: Optional[float] = Field(default=None, description="Cell border width") tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
[docs] class AGPieSeriesConfig(EmbeddedModel): """AG-Charts pie series configuration.""" type: Literal["pie"] = "pie" angleKey: str = Field(..., description="Key for pie slice angles") radiusKey: Optional[str] = Field( default=None, description="Key for pie slice radius" ) labelKey: Optional[str] = Field( default=None, description="Key for pie slice labels" ) legendItemKey: Optional[str] = Field( default=None, description="Key for legend item labels" ) calloutLabelKey: Optional[str] = Field( default=None, description="Key for callout labels" ) sectorLabelKey: Optional[str] = Field( default=None, description="Key for sector labels" ) visible: Optional[bool] = Field( default=True, description="Whether series is visible" ) showInLegend: Optional[bool] = Field(default=True, description="Show in legend") title: Optional[str] = Field(default=None, description="Series title") tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" ) data: List[Dict[str, Any]] = Field(default_factory=list, description="Chart data")
[docs] class AGDonutSeriesConfig(EmbeddedModel): """AG-Charts donut series configuration.""" type: Literal["donut"] = "donut" angleKey: str = Field(..., description="Key for donut slice angles") radiusKey: Optional[str] = Field( default=None, description="Key for donut slice radius" ) labelKey: Optional[str] = Field( default=None, description="Key for donut slice labels" ) legendItemKey: Optional[str] = Field( default=None, description="Key for legend item labels" ) calloutLabelKey: Optional[str] = Field( default=None, description="Key for callout labels" ) sectorLabelKey: Optional[str] = Field( default=None, description="Key for sector labels" ) innerRadiusRatio: Optional[float] = Field( default=0.6, description="Inner radius ratio" ) visible: Optional[bool] = Field( default=True, description="Whether series is visible" ) showInLegend: Optional[bool] = Field(default=True, description="Show in legend") title: Optional[str] = Field(default=None, description="Series title") tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Tooltip configuration" )
# Union type for all series configurations AGChartSeries = Union[ AGLineSeriesConfig, AGBarSeriesConfig, AGRangeBarSeriesConfig, AGColumnSeriesConfig, AGAreaSeriesConfig, AGScatterSeriesConfig, AGHeatmapSeriesConfig, AGPieSeriesConfig, AGDonutSeriesConfig, ] # Axis Configurations
[docs] class AGChartAxisConfig(EmbeddedModel): """AG-Charts axis configuration.""" type: Literal["category", "number", "time", "log"] = Field( ..., description="Axis type" ) position: Literal["top", "right", "bottom", "left"] = Field( ..., description="Axis position" ) title: Optional[str] = Field(default=None, description="Axis title") min: Optional[float] = Field(default=None, description="Minimum axis value") max: Optional[float] = Field(default=None, description="Maximum axis value") tick: Optional[Dict[str, Any]] = Field( default=None, description="Tick configuration" ) label: Optional[Dict[str, Any]] = Field( default=None, description="Label configuration" ) gridStyle: Optional[List[Dict[str, Any]]] = Field( default=None, description="Grid line style" )
# Legend Configuration
[docs] class AGChartLegendConfig(EmbeddedModel): """AG-Charts legend configuration.""" enabled: bool = Field(default=True, description="Enable legend") position: Literal["top", "right", "bottom", "left"] = Field( default="right", description="Legend position" ) spacing: float = Field(default=20, description="Legend spacing") item: Dict[str, Any] = Field( default_factory=dict, description="Legend item configuration" )
# Title Configuration
[docs] class AGChartTitleConfig(EmbeddedModel): """AG-Charts title configuration.""" text: str = Field("Chart Title", description="Title text")
# fontSize: Optional[int] = Field(default=16, description="Title font size") # fontWeight: Optional[str] = Field(default="bold", description="Title font weight") # color: Optional[str] = Field(default=None, description="Title color") # Subtitle Configuration
[docs] class AGChartSubtitleConfig(EmbeddedModel): """AG-Charts subtitle configuration.""" text: str = Field(..., description="Subtitle text") fontSize: Optional[int] = Field(default=12, description="Subtitle font size") color: Optional[str] = Field(default=None, description="Subtitle color")
# Frame Configuration
[docs] class AGChartFrameConfig(EmbeddedModel): """AG-Charts frame (border) configuration.""" enabled: bool = Field(default=True, description="Enable chart frame/border") stroke: str = Field(default="black", description="Frame stroke color") strokeWidth: float = Field(default=1, description="Frame stroke width") cornerRadius: float = Field(default=0, description="Frame corner radius") opacity: float = Field(default=1, description="Frame opacity")
# Main Chart Model
[docs] @simstack_model class ChartArtifactModel(Model): """AG-Charts configuration model.""" parent_id: Optional[ObjectId] = None # Chart data data: List[Dict[str, Any]] = Field(default_factory=list, description="Chart data") # Chart configuration title: AGChartTitleConfig = Field(..., description="Chart title configuration") # subtitle: AGChartSubtitleConfig = Field(..., description="Chart subtitle configuration") # Series configuration series: List[AGChartSeries] = Field( default_factory=list, description="Chart series configurations" ) # Axes configuration axes: List[AGChartAxisConfig] = Field( default_factory=list, description="Chart axes configurations" ) # # Legend configuration legend: AGChartLegendConfig = Field( default=AGChartLegendConfig(), description="Legend configuration" ) # # Chart styling and behavior width: int = Field(default=800, description="Chart width in pixels") height: int = Field(default=400, description="Chart height in pixels") padding: Optional[Dict[str, int]] = Field(default=None, description="Chart padding") background: Optional[Dict[str, Any]] = Field( default=None, description="Background configuration" ) frame: AGChartFrameConfig = Field( default=AGChartFrameConfig(enabled=False), description="Frame/border configuration" ) # Animation animation: Optional[Dict[str, Any]] = Field( default=None, description="Animation configuration" ) # Tooltip tooltip: Optional[Dict[str, Any]] = Field( default=None, description="Global tooltip configuration" ) # Theme theme: Optional[str] = Field(default="ag-default", description="Chart theme") # Additional options options: Optional[Dict[str, Any]] = Field( default_factory=dict, description="Additional chart options" )
[docs] def make_table_entries( self, max_recursion_level=1, drop_id=True, current_level=0, visited=None, field_prefix="", ): return {"title": self.title.text[:10]}
[docs] def make_column_defs_instance( self, table_name=None, max_recursion_level=1, drop_id=True, current_level=0, visited=None, field_prefix="", ): return [{"field": "title", "headerName": "Chart"}]
# Helper functions for creating specific chart types
[docs] def create_simple_line_chart( data: List[Dict[str, Any]], x_key: str, y_key: str, title: Optional[str] = None, parent_id: ObjectId = None, ) -> ChartArtifactModel: """Create a simple line chart.""" chart_title = ( AGChartTitleConfig(text=title) if title else AGChartTitleConfig(text="Chart") ) # subtitle = AGChartSubtitleConfig(text="Subtitle") series = [ AGLineSeriesConfig( type="line", xKey=x_key, yKey=y_key, title=y_key.title(), data=data ) ] axes = [ AGChartAxisConfig(type="number", position="bottom", title=x_key.title()), AGChartAxisConfig(type="number", position="left", title=y_key.title()), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, # subtitle=subtitle, series=series, axes=axes, )
[docs] def create_simple_bar_chart( data: List[Dict[str, Any]], x_key: str, y_key: str, title: Optional[str] = None, parent_id: Optional[ObjectId] = None, ) -> ChartArtifactModel: """Create a simple bar chart.""" chart_title = AGChartTitleConfig(text=title) if title else None series = [ AGColumnSeriesConfig(type="column", xKey=x_key, yKey=y_key, title=y_key.title()) ] axes = [ AGChartAxisConfig(type="category", position="bottom", title=x_key.title()), AGChartAxisConfig(type="number", position="left", title=y_key.title()), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series, axes=axes )
[docs] def create_simple_pie_chart( data: List[Dict[str, Any]], angle_key: str, label_key: str, title: Optional[str] = None, legend_item_key: Optional[str] = None, callout_label_key: Optional[str] = None, sector_label_key: Optional[str] = None, parent_id: Optional[ObjectId] = None, ) -> ChartArtifactModel: """Create a simple pie chart.""" chart_title = AGChartTitleConfig(text=title) if title else None series = [ AGPieSeriesConfig( type="pie", angleKey=angle_key, labelKey=label_key, legendItemKey=legend_item_key, calloutLabelKey=callout_label_key, sectorLabelKey=sector_label_key, title="Distribution", data=data, ) ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series )
[docs] def create_simple_range_bar_chart( data: List[Dict[str, Any]], x_key: str, y_low_key: str, y_high_key: str, title: Optional[str] = None, parent_id: Optional[ObjectId] = None, direction: Optional[Literal["horizontal", "vertical"]] = None, ) -> ChartArtifactModel: """Create a simple range-bar chart.""" chart_title = AGChartTitleConfig(text=title) if title else None series = [ AGRangeBarSeriesConfig( type="range-bar", xKey=x_key, yLowKey=y_low_key, yHighKey=y_high_key, title=f"{y_low_key.title()} - {y_high_key.title()}", direction=direction, data=data, ) ] axes = [ AGChartAxisConfig(type="category", position="bottom", title=x_key.title()), AGChartAxisConfig( type="number", position="left", title=f"{y_low_key.title()} / {y_high_key.title()}", ), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series, axes=axes )
[docs] def create_simple_area_chart( data: List[Dict[str, Any]], x_key: str, y_key: str, title: Optional[str] = None, parent_id: Optional[ObjectId] = None, ) -> ChartArtifactModel: """Create a simple area chart.""" chart_title = AGChartTitleConfig(text=title) if title else None series = [ AGAreaSeriesConfig(type="area", xKey=x_key, yKey=y_key, title=y_key.title()) ] axes = [ AGChartAxisConfig(type="category", position="bottom", title=x_key.title()), AGChartAxisConfig(type="number", position="left", title=y_key.title()), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series, axes=axes )
[docs] def create_simple_scatter_chart( data: List[Dict[str, Any]], x_key: str, y_key: str, title: Optional[str] = None, parent_id: Optional[ObjectId] = None, ) -> ChartArtifactModel: """Create a simple scatter chart.""" chart_title = AGChartTitleConfig(text=title) if title else None series = [ AGScatterSeriesConfig( type="scatter", xKey=x_key, yKey=y_key, title=y_key.title() ) ] axes = [ AGChartAxisConfig(type="number", position="bottom", title=x_key.title()), AGChartAxisConfig(type="number", position="left", title=y_key.title()), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series, axes=axes )
[docs] def create_simple_heatmap_chart( data: List[Dict[str, Any]], x_key: str, y_key: str, color_key: str, title: Optional[str] = None, parent_id: Optional[ObjectId] = None, x_axis_type: Literal["category", "number", "time", "log"] = "category", y_axis_type: Literal["category", "number", "time", "log"] = "category", ) -> ChartArtifactModel: """Create a simple heatmap chart.""" chart_title = ( AGChartTitleConfig(text=title) if title else AGChartTitleConfig(text="Chart") ) series = [ AGHeatmapSeriesConfig( type="heatmap", xKey=x_key, yKey=y_key, colorKey=color_key, title=color_key.title(), data=data, ) ] axes = [ AGChartAxisConfig(type=x_axis_type, position="bottom", title=x_key.title()), AGChartAxisConfig(type=y_axis_type, position="left", title=y_key.title()), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series, axes=axes )
[docs] def create_simple_donut_chart( data: List[Dict[str, Any]], angle_key: str, label_key: str, title: Optional[str] = None, legend_item_key: Optional[str] = None, callout_label_key: Optional[str] = None, sector_label_key: Optional[str] = None, inner_radius_ratio: float = 0.6, parent_id: Optional[ObjectId] = None, ) -> ChartArtifactModel: """Create a simple donut chart.""" chart_title = AGChartTitleConfig(text=title) if title else None series = [ AGDonutSeriesConfig( type="donut", angleKey=angle_key, labelKey=label_key, legendItemKey=legend_item_key, calloutLabelKey=callout_label_key, sectorLabelKey=sector_label_key, innerRadiusRatio=inner_radius_ratio, title="Distribution", ) ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series )
[docs] def create_multi_series_line_chart( data: List[Dict[str, Any]], x_key: str, y_keys: List[str], title: Optional[str] = None, parent_id: Optional[ObjectId] = None, ) -> ChartArtifactModel: """Create a line chart with multiple y-axis series.""" chart_title = AGChartTitleConfig(text=title) if title else AGChartTitleConfig(text="Chart") series = [] for y_key in y_keys: series.append( AGLineSeriesConfig( type="line", xKey=x_key, yKey=y_key, title=y_key.title(), data=data ) ) axes = [ AGChartAxisConfig(type="number", position="bottom", title=x_key.title()), AGChartAxisConfig(type="number", position="left", title="Values"), ] return ChartArtifactModel( parent_id=parent_id, data=data, title=chart_title, series=series, axes=axes, )