0
# Charts and Visualizations
1
2
Data visualization with chart views supporting pie charts, bar charts, line charts, and custom aggregation functions. The chart system provides comprehensive data visualization capabilities with Google Charts integration and flexible data aggregation.
3
4
## Capabilities
5
6
### BaseChartView Class
7
8
Foundation class for all chart views providing core charting functionality, data processing, and rendering capabilities with Google Charts integration.
9
10
```python { .api }
11
from flask_appbuilder.charts.views import BaseChartView
12
from flask_appbuilder.models.sqla.interface import SQLAInterface
13
14
class BaseChartView(BaseModelView):
15
"""
16
Base class for chart views providing core charting functionality.
17
"""
18
19
def __init__(self):
20
"""Initialize chart view with default configurations."""
21
22
def chart(self):
23
"""
24
Main chart rendering method.
25
26
Returns:
27
Rendered chart template with data and configuration
28
"""
29
30
# Chart configuration properties
31
chart_template = "appbuilder/general/charts/chart.html" # Chart template
32
chart_widget = None # Chart widget class
33
chart_title = "Chart" # Chart title
34
chart_type = "PieChart" # Google Charts type
35
chart_3d = False # Enable 3D rendering
36
width = 400 # Chart width in pixels
37
height = 300 # Chart height in pixels
38
39
# Data configuration
40
group_bys = [] # Grouping columns list
41
search_columns = [] # Searchable columns
42
label_columns = {} # Column labels
43
44
# Chart types available:
45
# - PieChart: Pie chart visualization
46
# - ColumnChart: Vertical bar chart
47
# - BarChart: Horizontal bar chart
48
# - LineChart: Line graph
49
# - AreaChart: Area chart
50
# - ScatterChart: Scatter plot
51
# - ComboChart: Combination chart
52
# - Gauge: Gauge visualization
53
# - GeoChart: Geographic chart
54
55
# Usage example
56
class SalesChartView(BaseChartView):
57
datamodel = SQLAInterface(Sale)
58
chart_title = "Sales Analysis"
59
chart_type = "ColumnChart"
60
width = 600
61
height = 400
62
63
# Define grouping and aggregation
64
group_bys = ['product_category']
65
search_columns = ['sale_date', 'product_category']
66
67
# Column labels for display
68
label_columns = {
69
'product_category': 'Product Category',
70
'total_amount': 'Total Sales'
71
}
72
73
# Register chart view
74
appbuilder.add_view(
75
SalesChartView,
76
"Sales Chart",
77
icon="fa-bar-chart",
78
category="Analytics"
79
)
80
```
81
82
### DirectByChartView Class
83
84
Direct data chart view for simple charts that display data directly without complex grouping or aggregation operations.
85
86
```python { .api }
87
from flask_appbuilder.charts.views import DirectByChartView
88
89
class DirectByChartView(BaseChartView):
90
"""
91
Direct chart view for simple data visualization without grouping.
92
Displays raw data directly in chart format.
93
"""
94
95
# Simple chart example - Monthly sales trend
96
class MonthlySalesChart(DirectByChartView):
97
datamodel = SQLAInterface(MonthlySale)
98
chart_title = "Monthly Sales Trend"
99
chart_type = "LineChart"
100
width = 800
101
height = 400
102
103
# Direct data mapping
104
search_columns = ['month', 'year']
105
label_columns = {
106
'month': 'Month',
107
'sales_total': 'Sales Amount'
108
}
109
110
# Product inventory levels
111
class InventoryChart(DirectByChartView):
112
datamodel = SQLAInterface(Product)
113
chart_title = "Current Inventory Levels"
114
chart_type = "BarChart"
115
116
# Show product inventory as horizontal bars
117
search_columns = ['name', 'category']
118
label_columns = {
119
'name': 'Product Name',
120
'stock_quantity': 'Stock Level'
121
}
122
123
# Base filter for active products only
124
base_filters = [['active', FilterEqual, True]]
125
126
# Geographic sales distribution
127
class SalesGeoChart(DirectByChartView):
128
datamodel = SQLAInterface(RegionalSale)
129
chart_title = "Sales by Region"
130
chart_type = "GeoChart"
131
width = 700
132
height = 500
133
134
label_columns = {
135
'country_code': 'Country',
136
'total_sales': 'Sales Volume'
137
}
138
```
139
140
### GroupByChartView Class
141
142
Group by chart view for aggregated data visualization supporting complex grouping operations and multiple aggregation functions.
143
144
```python { .api }
145
from flask_appbuilder.charts.views import GroupByChartView
146
from flask_appbuilder.models.group import aggregate_count, aggregate_sum, aggregate_avg
147
148
class GroupByChartView(BaseChartView):
149
"""
150
Chart view with grouping and aggregation capabilities.
151
Supports complex data analysis with multiple group-by operations.
152
"""
153
154
# Sales by department with aggregation
155
class DepartmentSalesChart(GroupByChartView):
156
datamodel = SQLAInterface(Sale)
157
chart_title = "Sales by Department"
158
chart_type = "PieChart"
159
chart_3d = True
160
161
# Group by department and sum sales amounts
162
group_bys = ['department.name']
163
164
# Search and filter options
165
search_columns = ['department.name', 'sale_date']
166
base_filters = [
167
['sale_date', FilterGreater, datetime.date(2023, 1, 1)]
168
]
169
170
label_columns = {
171
'department.name': 'Department',
172
'amount': 'Total Sales'
173
}
174
175
# Employee performance by month
176
class EmployeePerformanceChart(GroupByChartView):
177
datamodel = SQLAInterface(Sale)
178
chart_title = "Employee Performance by Month"
179
chart_type = "ColumnChart"
180
width = 900
181
height = 500
182
183
# Group by employee and month
184
group_bys = ['employee.name', 'MONTH(sale_date)']
185
186
search_columns = ['employee.name', 'sale_date']
187
label_columns = {
188
'employee.name': 'Employee',
189
'sale_date': 'Month',
190
'commission': 'Total Commission'
191
}
192
193
# Product sales with multiple metrics
194
class ProductAnalyticsChart(GroupByChartView):
195
datamodel = SQLAInterface(Sale)
196
chart_title = "Product Sales Analytics"
197
chart_type = "ComboChart"
198
199
# Group by product category
200
group_bys = ['product.category']
201
202
# Multiple aggregations: count, sum, average
203
definitions = [
204
{
205
'group': 'product.category',
206
'series': [
207
('COUNT(*)', 'Number of Sales'),
208
('SUM(amount)', 'Total Revenue'),
209
('AVG(amount)', 'Average Sale Value')
210
]
211
}
212
]
213
214
label_columns = {
215
'product.category': 'Category'
216
}
217
218
# Time-based trend analysis
219
class SalesTrendChart(GroupByChartView):
220
datamodel = SQLAInterface(Sale)
221
chart_title = "Sales Trend Analysis"
222
chart_type = "LineChart"
223
width = 1000
224
height = 400
225
226
# Group by date periods
227
group_bys = ['YEAR(sale_date)', 'MONTH(sale_date)']
228
229
search_columns = ['sale_date']
230
label_columns = {
231
'sale_date': 'Date',
232
'amount': 'Sales Amount'
233
}
234
```
235
236
### Chart Widgets
237
238
Widget classes for rendering different chart types with customizable templates and Google Charts integration.
239
240
```python { .api }
241
from flask_appbuilder.charts.widgets import ChartWidget, DirectChartWidget
242
243
class ChartWidget(RenderTemplateWidget):
244
"""Base chart widget for rendering Google Charts."""
245
246
template = "appbuilder/general/charts/chart.html"
247
248
def __call__(self, chart_data, chart_title="", chart_type="PieChart",
249
width=400, height=300, chart_3d=False, **kwargs):
250
"""
251
Render chart widget.
252
253
Parameters:
254
- chart_data: Chart data in Google Charts format
255
- chart_title: Chart title
256
- chart_type: Google Charts type
257
- width: Chart width in pixels
258
- height: Chart height in pixels
259
- chart_3d: Enable 3D rendering
260
- **kwargs: Additional chart options
261
262
Returns:
263
Rendered chart HTML with Google Charts JavaScript
264
"""
265
266
class DirectChartWidget(ChartWidget):
267
"""Widget for direct data charts without aggregation."""
268
269
template = "appbuilder/general/charts/direct_chart.html"
270
271
# Custom chart widget example
272
class CustomChartWidget(ChartWidget):
273
template = "my_custom_chart.html"
274
275
def __call__(self, **kwargs):
276
# Add custom chart options
277
kwargs.update({
278
'backgroundColor': '#f8f9fa',
279
'titleTextStyle': {'color': '#495057', 'fontSize': 18},
280
'legend': {'position': 'bottom', 'textStyle': {'fontSize': 12}}
281
})
282
283
return super(CustomChartWidget, self).__call__(**kwargs)
284
285
# Usage in chart views
286
class StyledSalesChart(GroupByChartView):
287
datamodel = SQLAInterface(Sale)
288
chart_widget = CustomChartWidget
289
chart_title = "Styled Sales Analysis"
290
chart_type = "ColumnChart"
291
292
# Advanced chart configuration
293
class AdvancedChart(GroupByChartView):
294
datamodel = SQLAInterface(Sale)
295
chart_title = "Advanced Sales Chart"
296
chart_type = "ComboChart"
297
298
# Custom chart options passed to Google Charts
299
chart_options = {
300
'vAxis': {'title': 'Sales Amount'},
301
'hAxis': {'title': 'Time Period'},
302
'series': {
303
0: {'type': 'columns', 'targetAxisIndex': 0},
304
1: {'type': 'line', 'targetAxisIndex': 1}
305
},
306
'vAxes': {
307
0: {'title': 'Revenue', 'format': 'currency'},
308
1: {'title': 'Count', 'format': 'decimal'}
309
}
310
}
311
```
312
313
### Aggregation Functions
314
315
Built-in and custom aggregation functions for data processing in chart views with support for mathematical operations and statistical calculations.
316
317
```python { .api }
318
from flask_appbuilder.models.group import aggregate_count, aggregate_sum, \
319
aggregate_avg, aggregate
320
321
# Built-in aggregation functions
322
@aggregate(label="Count")
323
def aggregate_count(items, col):
324
"""
325
Count aggregation function.
326
327
Parameters:
328
- items: List of model instances
329
- col: Column name (unused for count)
330
331
Returns:
332
Integer count of items
333
"""
334
return len(items)
335
336
@aggregate(label="Sum")
337
def aggregate_sum(items, col):
338
"""
339
Sum aggregation function.
340
341
Parameters:
342
- items: List of model instances
343
- col: Column name to sum
344
345
Returns:
346
Sum of column values
347
"""
348
return sum(getattr(item, col, 0) or 0 for item in items)
349
350
@aggregate(label="Average")
351
def aggregate_avg(items, col):
352
"""
353
Average aggregation function.
354
355
Parameters:
356
- items: List of model instances
357
- col: Column name to average
358
359
Returns:
360
Average of column values
361
"""
362
values = [getattr(item, col, 0) or 0 for item in items]
363
return sum(values) / len(values) if values else 0
364
365
# Custom aggregation functions
366
@aggregate(label="Maximum")
367
def aggregate_max(items, col):
368
"""Maximum value aggregation."""
369
values = [getattr(item, col, 0) or 0 for item in items]
370
return max(values) if values else 0
371
372
@aggregate(label="Minimum")
373
def aggregate_min(items, col):
374
"""Minimum value aggregation."""
375
values = [getattr(item, col, 0) or 0 for item in items]
376
return min(values) if values else 0
377
378
@aggregate(label="Standard Deviation")
379
def aggregate_stddev(items, col):
380
"""Standard deviation aggregation."""
381
import statistics
382
values = [getattr(item, col, 0) or 0 for item in items]
383
return statistics.stdev(values) if len(values) > 1 else 0
384
385
@aggregate(label="Median")
386
def aggregate_median(items, col):
387
"""Median value aggregation."""
388
import statistics
389
values = [getattr(item, col, 0) or 0 for item in items]
390
return statistics.median(values) if values else 0
391
392
# Complex business aggregation
393
@aggregate(label="Profit Margin")
394
def aggregate_profit_margin(items, col):
395
"""Calculate profit margin percentage."""
396
total_revenue = sum(getattr(item, 'revenue', 0) or 0 for item in items)
397
total_cost = sum(getattr(item, 'cost', 0) or 0 for item in items)
398
399
if total_revenue > 0:
400
return ((total_revenue - total_cost) / total_revenue) * 100
401
return 0
402
403
# Usage in chart views
404
class ProfitAnalysisChart(GroupByChartView):
405
datamodel = SQLAInterface(Sale)
406
chart_title = "Profit Analysis by Product"
407
chart_type = "ColumnChart"
408
409
# Use custom aggregation
410
group_bys = ['product.name']
411
412
# Define aggregation in chart configuration
413
definitions = [
414
{
415
'group': 'product.name',
416
'series': [
417
('aggregate_sum', 'Total Revenue'),
418
('aggregate_profit_margin', 'Profit Margin %')
419
]
420
}
421
]
422
423
# Time-based aggregation
424
@aggregate(label="Monthly Growth Rate")
425
def aggregate_growth_rate(items, col):
426
"""Calculate month-over-month growth rate."""
427
# Sort items by date
428
sorted_items = sorted(items, key=lambda x: getattr(x, 'date'))
429
430
if len(sorted_items) < 2:
431
return 0
432
433
current_value = getattr(sorted_items[-1], col, 0) or 0
434
previous_value = getattr(sorted_items[-2], col, 0) or 0
435
436
if previous_value > 0:
437
return ((current_value - previous_value) / previous_value) * 100
438
return 0
439
440
# Weighted average aggregation
441
@aggregate(label="Weighted Average")
442
def aggregate_weighted_avg(items, col, weight_col='quantity'):
443
"""Calculate weighted average."""
444
total_weight = sum(getattr(item, weight_col, 0) or 0 for item in items)
445
446
if total_weight > 0:
447
weighted_sum = sum(
448
(getattr(item, col, 0) or 0) * (getattr(item, weight_col, 0) or 0)
449
for item in items
450
)
451
return weighted_sum / total_weight
452
return 0
453
```
454
455
### Chart Data Processing
456
457
Advanced data processing capabilities for chart views including filtering, transformation, and custom data preparation.
458
459
```python { .api }
460
# Custom data processing in chart views
461
class CustomDataChart(GroupByChartView):
462
datamodel = SQLAInterface(Sale)
463
chart_title = "Custom Data Processing"
464
465
def get_group_by_data(self, group_bys, **kwargs):
466
"""
467
Override data processing for custom logic.
468
469
Parameters:
470
- group_bys: List of grouping columns
471
- **kwargs: Additional parameters
472
473
Returns:
474
Processed chart data
475
"""
476
# Get base data
477
data = super(CustomDataChart, self).get_group_by_data(group_bys, **kwargs)
478
479
# Apply custom transformations
480
transformed_data = []
481
for row in data:
482
# Custom business logic
483
transformed_row = self.transform_data_row(row)
484
transformed_data.append(transformed_row)
485
486
return transformed_data
487
488
def transform_data_row(self, row):
489
"""Apply custom transformations to data row."""
490
# Example: Convert currency, apply business rules, etc.
491
if 'amount' in row:
492
row['amount'] = self.format_currency(row['amount'])
493
494
return row
495
496
def format_currency(self, amount):
497
"""Format amount as currency."""
498
return f"${amount:,.2f}"
499
500
# Multi-series chart with custom data
501
class MultiSeriesChart(GroupByChartView):
502
datamodel = SQLAInterface(Sale)
503
chart_title = "Multi-Series Analysis"
504
chart_type = "LineChart"
505
506
def get_chart_data(self, group_by, **kwargs):
507
"""Generate multi-series chart data."""
508
# Get data for each series
509
series_data = {}
510
511
# Revenue series
512
revenue_data = self.get_series_data('revenue', group_by, **kwargs)
513
series_data['Revenue'] = revenue_data
514
515
# Profit series
516
profit_data = self.get_series_data('profit', group_by, **kwargs)
517
series_data['Profit'] = profit_data
518
519
# Format for Google Charts
520
return self.format_multi_series_data(series_data)
521
522
def get_series_data(self, metric, group_by, **kwargs):
523
"""Get data for specific metric series."""
524
# Custom query for metric
525
query = self.datamodel.get_query()
526
# Apply filters and aggregation
527
return query.all()
528
529
def format_multi_series_data(self, series_data):
530
"""Format data for multi-series chart."""
531
# Convert to Google Charts format
532
formatted_data = []
533
# Implementation details...
534
return formatted_data
535
536
# Real-time chart with data refresh
537
class RealTimeChart(GroupByChartView):
538
datamodel = SQLAInterface(Sale)
539
chart_title = "Real-Time Sales"
540
541
# Auto-refresh configuration
542
refresh_interval = 30 # seconds
543
544
def get_live_data(self):
545
"""Get live data for real-time updates."""
546
# Query recent data
547
cutoff_time = datetime.datetime.now() - datetime.timedelta(hours=1)
548
549
query = self.datamodel.get_query().filter(
550
Sale.created_on >= cutoff_time
551
)
552
553
return query.all()
554
555
@expose('/live-data/')
556
def live_data_endpoint(self):
557
"""AJAX endpoint for live data updates."""
558
data = self.get_live_data()
559
processed_data = self.process_live_data(data)
560
561
return jsonify({
562
'success': True,
563
'data': processed_data,
564
'timestamp': datetime.datetime.now().isoformat()
565
})
566
567
# Chart with drill-down capability
568
class DrillDownChart(GroupByChartView):
569
datamodel = SQLAInterface(Sale)
570
chart_title = "Sales with Drill-Down"
571
572
@expose('/drill-down/<category>/')
573
def drill_down(self, category):
574
"""Drill-down to detailed view for specific category."""
575
# Get detailed data for category
576
detailed_data = self.get_category_details(category)
577
578
# Render detailed chart
579
return self.render_template(
580
'detailed_chart.html',
581
category=category,
582
data=detailed_data
583
)
584
585
def get_category_details(self, category):
586
"""Get detailed breakdown for category."""
587
query = self.datamodel.get_query().filter(
588
Sale.category == category
589
)
590
return query.all()
591
```