or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions-hooks.mdcharts.mdcli-tools.mdconstants-exceptions.mdcore-framework.mddatabase-models.mdforms-fields.mdindex.mdrest-api.mdsecurity.mdviews-crud.md

charts.mddocs/

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

```