0
# Visualization System
1
2
Extensible visualization system supporting 40+ chart types with custom plugin architecture and data processing pipeline.
3
4
## Capabilities
5
6
### Base Visualization Classes
7
8
Core visualization framework for creating chart types.
9
10
```python { .api }
11
class BaseViz:
12
"""Base class for all visualizations."""
13
14
viz_type: str # Unique chart type identifier
15
verbose_name: str # Display name for chart type
16
is_timeseries: bool = False # Whether chart supports time series
17
default_are_zeros: bool = True # How to handle missing data
18
credits: str = "" # Attribution for chart type
19
20
def __init__(self, datasource: BaseDatasource, form_data: Dict[str, Any],
21
force: bool = False):
22
"""
23
Initialize visualization.
24
25
Args:
26
datasource: Data source for chart
27
form_data: Chart configuration from UI
28
force: Force refresh of cached data
29
"""
30
31
def get_query_object(self) -> QueryObject:
32
"""
33
Build query object from form data.
34
35
Returns:
36
Query object for data retrieval
37
"""
38
39
def get_data(self, df: pd.DataFrame) -> VizData:
40
"""
41
Process DataFrame into visualization-ready format.
42
43
Args:
44
df: Raw query results
45
46
Returns:
47
Processed data for frontend rendering
48
"""
49
50
def get_csv(self) -> str:
51
"""
52
Export chart data as CSV.
53
54
Returns:
55
CSV-formatted chart data
56
"""
57
58
def get_json_data(self, force: bool = False) -> Dict[str, Any]:
59
"""
60
Get chart data as JSON.
61
62
Args:
63
force: Force refresh of cached data
64
65
Returns:
66
Chart data and metadata
67
"""
68
69
class TimeSeriesViz(BaseViz):
70
"""Base class for time series visualizations."""
71
72
is_timeseries: bool = True
73
74
def process_data(self, df: pd.DataFrame,
75
aggregate: bool = False) -> Dict[str, Any]:
76
"""
77
Process time series data.
78
79
Args:
80
df: Time series DataFrame
81
aggregate: Whether to aggregate data
82
83
Returns:
84
Processed time series data
85
"""
86
87
def to_series(self, df: pd.DataFrame, classed: str = "",
88
title_suffix: str = "") -> List[Dict[str, Any]]:
89
"""
90
Convert DataFrame to time series format.
91
92
Args:
93
df: Source DataFrame
94
classed: CSS class for series
95
title_suffix: Suffix for series titles
96
97
Returns:
98
List of time series objects
99
"""
100
```
101
102
### Chart Type Registry
103
104
Registry system for available chart types and their implementations.
105
106
```python { .api }
107
# Chart Type Registry
108
viz_types: Dict[str, Type[BaseViz]] = {
109
'table': TableViz,
110
'bar': DistributionBarViz,
111
'line': LineViz,
112
'area': AreaViz,
113
'pie': PieViz,
114
'scatter': ScatterViz,
115
'bubble': BubbleViz,
116
'histogram': HistogramViz,
117
'box_plot': BoxPlotViz,
118
'sunburst': SunburstViz,
119
'treemap': TreemapViz,
120
'heatmap': HeatmapViz,
121
'deck_scatter': DeckScatterViz,
122
'deck_arc': DeckArcViz,
123
'deck_hex': DeckHexViz,
124
'deck_grid': DeckGridViz,
125
'deck_polygon': DeckPolygonViz,
126
'deck_geojson': DeckGeoJsonViz,
127
'pivot_table': PivotTableViz,
128
'paired_ttest': PairedTTestViz,
129
'rose': RoseViz,
130
'partition': PartitionViz,
131
'event_flow': EventFlowViz,
132
'parallel_coordinates': ParallelCoordinatesViz,
133
'sankey': SankeyViz,
134
'chord': ChordViz,
135
'country_map': CountryMapViz,
136
'world_map': WorldMapViz,
137
'filter_box': FilterBoxViz,
138
'iframe': IFrameViz,
139
'para': ParaViz,
140
'markup': MarkupViz,
141
'separator': SeparatorViz,
142
'word_cloud': WordCloudViz,
143
'mapbox': MapboxViz,
144
}
145
146
def get_viz(viz_type: str, datasource: BaseDatasource,
147
form_data: Dict[str, Any] = None, **kwargs) -> BaseViz:
148
"""
149
Get visualization instance by type.
150
151
Args:
152
viz_type: Chart type identifier
153
datasource: Data source
154
form_data: Chart configuration
155
156
Returns:
157
Visualization instance
158
159
Raises:
160
Exception: If viz_type not found
161
"""
162
163
def get_all_viz_types() -> List[Dict[str, Any]]:
164
"""
165
Get metadata for all available chart types.
166
167
Returns:
168
List of chart type metadata
169
"""
170
```
171
172
### Common Chart Types
173
174
Implementation of popular chart types.
175
176
```python { .api }
177
class TableViz(BaseViz):
178
"""Tabular data visualization."""
179
180
viz_type = "table"
181
verbose_name = "Table View"
182
is_timeseries = False
183
184
def get_data(self, df: pd.DataFrame) -> VizData:
185
"""
186
Process data for table display.
187
188
Args:
189
df: Query results DataFrame
190
191
Returns:
192
Table data with formatting and pagination
193
"""
194
195
class LineViz(TimeSeriesViz):
196
"""Line chart visualization."""
197
198
viz_type = "line"
199
verbose_name = "Time Series - Line Chart"
200
default_are_zeros = False
201
202
def get_data(self, df: pd.DataFrame) -> VizData:
203
"""
204
Process data for line chart.
205
206
Args:
207
df: Time series DataFrame
208
209
Returns:
210
Line chart data with series and formatting
211
"""
212
213
class BarViz(BaseViz):
214
"""Bar chart visualization."""
215
216
viz_type = "bar"
217
verbose_name = "Bar Chart"
218
219
def get_data(self, df: pd.DataFrame) -> VizData:
220
"""
221
Process data for bar chart.
222
223
Args:
224
df: Grouped DataFrame
225
226
Returns:
227
Bar chart data with categories and values
228
"""
229
230
class PieViz(BaseViz):
231
"""Pie chart visualization."""
232
233
viz_type = "pie"
234
verbose_name = "Pie Chart"
235
236
def get_data(self, df: pd.DataFrame) -> VizData:
237
"""
238
Process data for pie chart.
239
240
Args:
241
df: Aggregated DataFrame
242
243
Returns:
244
Pie chart data with segments and percentages
245
"""
246
247
class ScatterViz(BaseViz):
248
"""Scatter plot visualization."""
249
250
viz_type = "scatter"
251
verbose_name = "Scatter Plot"
252
253
def get_data(self, df: pd.DataFrame) -> VizData:
254
"""
255
Process data for scatter plot.
256
257
Args:
258
df: Point data DataFrame
259
260
Returns:
261
Scatter plot data with coordinates and metadata
262
"""
263
```
264
265
### Query Object System
266
267
System for translating UI form data into database queries.
268
269
```python { .api }
270
class QueryObject:
271
"""Query specification for data retrieval."""
272
273
def __init__(self,
274
datasource: BaseDatasource,
275
metrics: List[str] = None,
276
groupby: List[str] = None,
277
columns: List[str] = None,
278
granularity: str = None,
279
since: str = None,
280
until: str = None,
281
filters: List[Dict[str, Any]] = None,
282
row_limit: int = None,
283
row_offset: int = None,
284
order_desc: bool = True,
285
extras: Dict[str, Any] = None):
286
"""
287
Initialize query object.
288
289
Args:
290
datasource: Target datasource
291
metrics: List of metrics to calculate
292
groupby: Columns to group by
293
columns: Specific columns to include
294
granularity: Time granularity for time series
295
since: Start time for time range
296
until: End time for time range
297
filters: List of filter conditions
298
row_limit: Maximum rows to return
299
row_offset: Number of rows to skip
300
order_desc: Sort order (descending if True)
301
extras: Additional query parameters
302
"""
303
self.datasource = datasource
304
self.metrics = metrics or []
305
self.groupby = groupby or []
306
self.columns = columns or []
307
self.granularity = granularity
308
self.since = since
309
self.until = until
310
self.filters = filters or []
311
self.row_limit = row_limit
312
self.row_offset = row_offset
313
self.order_desc = order_desc
314
self.extras = extras or {}
315
316
def to_dict(self) -> Dict[str, Any]:
317
"""Convert query object to dictionary."""
318
319
@classmethod
320
def from_dict(cls, obj_dict: Dict[str, Any]) -> 'QueryObject':
321
"""Create query object from dictionary."""
322
323
def get_query_results(query_obj: QueryObject,
324
force_cached: bool = False) -> Dict[str, Any]:
325
"""
326
Execute query and return results.
327
328
Args:
329
query_obj: Query specification
330
force_cached: Use cached results if available
331
332
Returns:
333
Query results with data and metadata
334
"""
335
```
336
337
### Data Processing Pipeline
338
339
System for processing raw query results into visualization formats.
340
341
```python { .api }
342
class DataProcessor:
343
"""Data processing utilities for visualizations."""
344
345
@staticmethod
346
def pivot_df(df: pd.DataFrame, rows: List[str], cols: List[str],
347
metric: str, aggfunc: str = 'sum',
348
fill_value: Any = 0) -> pd.DataFrame:
349
"""
350
Pivot DataFrame for cross-tabulation.
351
352
Args:
353
df: Source DataFrame
354
rows: Row dimension columns
355
cols: Column dimension columns
356
metric: Value column to aggregate
357
aggfunc: Aggregation function
358
fill_value: Value for missing cells
359
360
Returns:
361
Pivoted DataFrame
362
"""
363
364
@staticmethod
365
def flatten_df(df: pd.DataFrame) -> pd.DataFrame:
366
"""
367
Flatten DataFrame with MultiIndex columns.
368
369
Args:
370
df: DataFrame to flatten
371
372
Returns:
373
DataFrame with single-level column index
374
"""
375
376
@staticmethod
377
def apply_time_grain(df: pd.DataFrame, time_grain: str,
378
time_col: str) -> pd.DataFrame:
379
"""
380
Apply time granularity to DataFrame.
381
382
Args:
383
df: Time series DataFrame
384
time_grain: Granularity (P1D, PT1H, etc.)
385
time_col: Datetime column name
386
387
Returns:
388
DataFrame aggregated to specified granularity
389
"""
390
391
@staticmethod
392
def post_process(df: pd.DataFrame,
393
form_data: Dict[str, Any]) -> pd.DataFrame:
394
"""
395
Apply post-processing operations to DataFrame.
396
397
Args:
398
df: Processed DataFrame
399
form_data: Chart configuration
400
401
Returns:
402
Post-processed DataFrame
403
"""
404
405
def df_to_records(df: pd.DataFrame) -> List[Dict[str, Any]]:
406
"""Convert DataFrame to list of records."""
407
408
def apply_row_limit(df: pd.DataFrame, limit: int) -> pd.DataFrame:
409
"""Apply row limit to DataFrame."""
410
411
def apply_filters(df: pd.DataFrame,
412
filters: List[Dict[str, Any]]) -> pd.DataFrame:
413
"""Apply filter conditions to DataFrame."""
414
```
415
416
### Plugin System
417
418
Architecture for creating custom chart types and visualizations.
419
420
```python { .api }
421
class VizPlugin:
422
"""Base class for visualization plugins."""
423
424
viz_type: str # Unique identifier
425
verbose_name: str # Display name
426
category: str = "Other" # Plugin category
427
428
@classmethod
429
def get_viz_class(cls) -> Type[BaseViz]:
430
"""
431
Get visualization class for this plugin.
432
433
Returns:
434
BaseViz subclass
435
"""
436
437
@classmethod
438
def get_form_data_spec(cls) -> Dict[str, Any]:
439
"""
440
Get form specification for chart configuration.
441
442
Returns:
443
Form field specifications
444
"""
445
446
@classmethod
447
def register(cls) -> None:
448
"""Register plugin with visualization system."""
449
450
def load_viz_plugins(plugin_dir: str) -> None:
451
"""
452
Load visualization plugins from directory.
453
454
Args:
455
plugin_dir: Directory containing plugin modules
456
"""
457
458
def register_viz_type(viz_type: str, viz_class: Type[BaseViz]) -> None:
459
"""
460
Register new visualization type.
461
462
Args:
463
viz_type: Unique chart type identifier
464
viz_class: Visualization implementation class
465
"""
466
```
467
468
**Usage Examples:**
469
470
```python
471
# Create custom visualization
472
class MyCustomViz(BaseViz):
473
viz_type = "my_custom"
474
verbose_name = "My Custom Chart"
475
476
def get_data(self, df):
477
# Custom data processing logic
478
return {'data': df.to_dict('records')}
479
480
# Register custom visualization
481
register_viz_type("my_custom", MyCustomViz)
482
483
# Use visualization in chart
484
viz = get_viz("my_custom", datasource, form_data)
485
chart_data = viz.get_json_data()
486
```
487
488
## Visualization Configuration
489
490
### Chart Form Data
491
492
```python { .api }
493
# Common form data fields across chart types
494
FormData = {
495
'datasource': str, # Datasource identifier
496
'viz_type': str, # Chart type
497
'metrics': List[str], # Metrics to display
498
'groupby': List[str], # Grouping columns
499
'time_grain_sqla': str, # Time granularity
500
'since': str, # Start time
501
'until': str, # End time
502
'filters': List[Dict], # Filter conditions
503
'row_limit': int, # Row limit
504
'order_desc': bool, # Sort order
505
'color_scheme': str, # Color palette
506
'show_legend': bool, # Show/hide legend
507
'rich_tooltip': bool, # Enhanced tooltips
508
'y_axis_format': str, # Y-axis number format
509
}
510
```