Spaces:
Running
Running
maxschulz-COL
commited on
Commit
•
8f9924d
1
Parent(s):
c5450ab
Upload 9 files
Browse files- app.py +685 -0
- assets/css/custom.css +3 -0
- assets/favicon.ico +0 -0
- assets/images/app.svg +9 -0
- assets/images/icons/download.svg +3 -0
- assets/images/icons/filters.svg +11 -0
- assets/images/icons/line-chart.svg +7 -0
- assets/images/icons/use-case.svg +3 -0
- assets/images/logo.svg +3 -0
app.py
ADDED
@@ -0,0 +1,685 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Example app to show all features of Vizro."""
|
2 |
+
|
3 |
+
from time import sleep
|
4 |
+
from typing import List, Literal, Optional
|
5 |
+
|
6 |
+
import pandas as pd
|
7 |
+
import plotly.graph_objects as go
|
8 |
+
import vizro.models as vm
|
9 |
+
import vizro.plotly.express as px
|
10 |
+
from dash import dash_table, html
|
11 |
+
from vizro import Vizro
|
12 |
+
from vizro.actions import export_data, filter_interaction
|
13 |
+
from vizro.models.types import capture
|
14 |
+
from vizro.tables import dash_ag_grid, dash_data_table
|
15 |
+
|
16 |
+
iris = px.data.iris()
|
17 |
+
tips = px.data.tips()
|
18 |
+
stocks = px.data.stocks(datetimes=True)
|
19 |
+
gapminder_2007 = px.data.gapminder().query("year == 2007")
|
20 |
+
waterfall_df = pd.DataFrame(
|
21 |
+
{
|
22 |
+
"measure": ["relative", "relative", "total", "relative", "relative", "total"],
|
23 |
+
"x": ["Sales", "Consulting", "Net revenue", "Purchases", "Other expenses", "Profit before tax"],
|
24 |
+
"text": ["+60", "+80", "", "-40", "-20", "Total"],
|
25 |
+
"y": [60, 80, 0, -40, -20, 0],
|
26 |
+
}
|
27 |
+
)
|
28 |
+
|
29 |
+
# HOME ------------------------------------------------------------------------
|
30 |
+
home = vm.Page(
|
31 |
+
title="Homepage",
|
32 |
+
layout=vm.Layout(grid=[[0, 1], [2, 3]], row_gap="16px", col_gap="24px"),
|
33 |
+
components=[
|
34 |
+
vm.Card(
|
35 |
+
text="""
|
36 |
+
![](assets/images/icons/line-chart.svg#icon-top)
|
37 |
+
|
38 |
+
### Components
|
39 |
+
|
40 |
+
Main components of Vizro include **charts**, **tables**, **cards**, **containers**,
|
41 |
+
**buttons** and **tabs**.
|
42 |
+
""",
|
43 |
+
href="/graphs",
|
44 |
+
),
|
45 |
+
vm.Card(
|
46 |
+
text="""
|
47 |
+
![](assets/images/icons/filters.svg#icon-top)
|
48 |
+
|
49 |
+
### Controls
|
50 |
+
|
51 |
+
Vizro has two different control types **Filter** and **Parameter**.
|
52 |
+
|
53 |
+
You can use any pre-existing selector inside the **Filter** or **Parameter**:
|
54 |
+
|
55 |
+
* Dropdown
|
56 |
+
* Checklist
|
57 |
+
* RadioItems
|
58 |
+
* RangeSlider
|
59 |
+
* Slider
|
60 |
+
* DatePicker
|
61 |
+
""",
|
62 |
+
href="/filters",
|
63 |
+
),
|
64 |
+
vm.Card(
|
65 |
+
text="""
|
66 |
+
![](assets/images/icons/download.svg#icon-top)
|
67 |
+
|
68 |
+
### Actions
|
69 |
+
|
70 |
+
Standard predefined actions are made available including **export data** and **filter interactions**.
|
71 |
+
""",
|
72 |
+
href="/export-data",
|
73 |
+
),
|
74 |
+
vm.Card(
|
75 |
+
text="""
|
76 |
+
![](assets/images/icons/use-case.svg#icon-top)
|
77 |
+
|
78 |
+
### Extensions
|
79 |
+
|
80 |
+
Vizro enables customization of **plotly express** and **graph object charts** as well as
|
81 |
+
creating custom components based on Dash.
|
82 |
+
""",
|
83 |
+
href="/custom-charts",
|
84 |
+
),
|
85 |
+
],
|
86 |
+
)
|
87 |
+
|
88 |
+
# COMPONENTS ------------------------------------------------------------------
|
89 |
+
graphs = vm.Page(
|
90 |
+
title="Graphs",
|
91 |
+
components=[
|
92 |
+
vm.Graph(
|
93 |
+
figure=px.scatter_matrix(
|
94 |
+
iris,
|
95 |
+
dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"],
|
96 |
+
color="species",
|
97 |
+
)
|
98 |
+
)
|
99 |
+
],
|
100 |
+
controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))],
|
101 |
+
)
|
102 |
+
|
103 |
+
ag_grid = vm.Page(
|
104 |
+
title="AG Grid",
|
105 |
+
components=[
|
106 |
+
vm.AgGrid(
|
107 |
+
title="Dash AG Grid", figure=dash_ag_grid(data_frame=gapminder_2007, dashGridOptions={"pagination": True})
|
108 |
+
)
|
109 |
+
],
|
110 |
+
controls=[vm.Filter(column="continent")],
|
111 |
+
)
|
112 |
+
|
113 |
+
table = vm.Page(
|
114 |
+
title="Table",
|
115 |
+
components=[
|
116 |
+
vm.Table(
|
117 |
+
title="Dash DataTable",
|
118 |
+
figure=dash_data_table(data_frame=gapminder_2007),
|
119 |
+
)
|
120 |
+
],
|
121 |
+
controls=[vm.Filter(column="continent")],
|
122 |
+
)
|
123 |
+
|
124 |
+
cards = vm.Page(
|
125 |
+
title="Cards",
|
126 |
+
components=[
|
127 |
+
vm.Card(
|
128 |
+
text="""
|
129 |
+
# Header level 1 <h1>
|
130 |
+
|
131 |
+
## Header level 2 <h2>
|
132 |
+
|
133 |
+
### Header level 3 <h3>
|
134 |
+
|
135 |
+
#### Header level 4 <h4>
|
136 |
+
"""
|
137 |
+
),
|
138 |
+
vm.Card(
|
139 |
+
text="""
|
140 |
+
### Paragraphs
|
141 |
+
Commodi repudiandae consequuntur voluptatum laborum numquam blanditiis harum quisquam eius sed odit.
|
142 |
+
|
143 |
+
Fugiat iusto fuga praesentium option, eaque rerum! Provident similique accusantium nemo autem.
|
144 |
+
|
145 |
+
Obcaecati tenetur iure eius earum ut molestias architecto voluptate aliquam nihil, eveniet aliquid.
|
146 |
+
|
147 |
+
Culpa officia aut! Impedit sit sunt quaerat, odit, tenetur error, harum nesciunt ipsum debitis quas.
|
148 |
+
"""
|
149 |
+
),
|
150 |
+
vm.Card(
|
151 |
+
text="""
|
152 |
+
### Block Quotes
|
153 |
+
|
154 |
+
>
|
155 |
+
> A block quote is a long quotation, indented to create a separate block of text.
|
156 |
+
>
|
157 |
+
"""
|
158 |
+
),
|
159 |
+
vm.Card(
|
160 |
+
text="""
|
161 |
+
### Lists
|
162 |
+
|
163 |
+
* Item A
|
164 |
+
* Sub Item 1
|
165 |
+
* Sub Item 2
|
166 |
+
* Item B
|
167 |
+
"""
|
168 |
+
),
|
169 |
+
vm.Card(
|
170 |
+
text="""
|
171 |
+
### Emphasis
|
172 |
+
|
173 |
+
This word will be *italic*
|
174 |
+
|
175 |
+
This word will be **bold**
|
176 |
+
|
177 |
+
This word will be _**bold and italic**_
|
178 |
+
"""
|
179 |
+
),
|
180 |
+
],
|
181 |
+
)
|
182 |
+
|
183 |
+
button = vm.Page(
|
184 |
+
title="Button",
|
185 |
+
layout=vm.Layout(grid=[[0], [0], [0], [0], [1]]),
|
186 |
+
components=[
|
187 |
+
vm.Graph(
|
188 |
+
figure=px.scatter(
|
189 |
+
iris,
|
190 |
+
x="sepal_width",
|
191 |
+
y="sepal_length",
|
192 |
+
color="species",
|
193 |
+
size="petal_length",
|
194 |
+
),
|
195 |
+
),
|
196 |
+
vm.Button(text="Export data", actions=[vm.Action(function=export_data())]),
|
197 |
+
],
|
198 |
+
controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))],
|
199 |
+
)
|
200 |
+
|
201 |
+
containers = vm.Page(
|
202 |
+
title="Containers",
|
203 |
+
components=[
|
204 |
+
vm.Container(
|
205 |
+
title="Container I",
|
206 |
+
layout=vm.Layout(grid=[[0, 1]]),
|
207 |
+
components=[
|
208 |
+
vm.Graph(
|
209 |
+
figure=px.scatter(
|
210 |
+
iris,
|
211 |
+
x="sepal_length",
|
212 |
+
y="petal_width",
|
213 |
+
color="species",
|
214 |
+
title="Container I - Scatter",
|
215 |
+
)
|
216 |
+
),
|
217 |
+
vm.Graph(
|
218 |
+
figure=px.bar(
|
219 |
+
iris,
|
220 |
+
x="sepal_length",
|
221 |
+
y="sepal_width",
|
222 |
+
color="species",
|
223 |
+
title="Container I - Bar",
|
224 |
+
)
|
225 |
+
),
|
226 |
+
],
|
227 |
+
),
|
228 |
+
vm.Container(
|
229 |
+
title="Container II",
|
230 |
+
components=[
|
231 |
+
vm.Graph(
|
232 |
+
figure=px.scatter(
|
233 |
+
iris,
|
234 |
+
x="sepal_width",
|
235 |
+
y="sepal_length",
|
236 |
+
color="species",
|
237 |
+
marginal_y="violin",
|
238 |
+
marginal_x="box",
|
239 |
+
title="Container II - Scatter",
|
240 |
+
)
|
241 |
+
)
|
242 |
+
],
|
243 |
+
),
|
244 |
+
],
|
245 |
+
)
|
246 |
+
|
247 |
+
tab_1 = vm.Container(
|
248 |
+
title="Tab I",
|
249 |
+
components=[
|
250 |
+
vm.Graph(
|
251 |
+
figure=px.bar(
|
252 |
+
gapminder_2007,
|
253 |
+
title="Graph 1",
|
254 |
+
x="continent",
|
255 |
+
y="lifeExp",
|
256 |
+
color="continent",
|
257 |
+
),
|
258 |
+
),
|
259 |
+
vm.Graph(
|
260 |
+
figure=px.box(
|
261 |
+
gapminder_2007,
|
262 |
+
title="Graph 2",
|
263 |
+
x="continent",
|
264 |
+
y="lifeExp",
|
265 |
+
color="continent",
|
266 |
+
),
|
267 |
+
),
|
268 |
+
],
|
269 |
+
)
|
270 |
+
|
271 |
+
tab_2 = vm.Container(
|
272 |
+
title="Tab II",
|
273 |
+
components=[
|
274 |
+
vm.Graph(
|
275 |
+
figure=px.scatter(
|
276 |
+
gapminder_2007,
|
277 |
+
title="Graph 3",
|
278 |
+
x="gdpPercap",
|
279 |
+
y="lifeExp",
|
280 |
+
size="pop",
|
281 |
+
color="continent",
|
282 |
+
),
|
283 |
+
),
|
284 |
+
],
|
285 |
+
)
|
286 |
+
|
287 |
+
tabs = vm.Page(title="Tabs", components=[vm.Tabs(tabs=[tab_1, tab_2])], controls=[vm.Filter(column="continent")])
|
288 |
+
|
289 |
+
# CONTROLS --------------------------------------------------------------------
|
290 |
+
filters = vm.Page(
|
291 |
+
title="Filters",
|
292 |
+
components=[
|
293 |
+
vm.Graph(
|
294 |
+
figure=px.scatter(
|
295 |
+
iris,
|
296 |
+
x="sepal_length",
|
297 |
+
y="petal_width",
|
298 |
+
color="species",
|
299 |
+
)
|
300 |
+
),
|
301 |
+
vm.Graph(
|
302 |
+
id="scatter_chart2",
|
303 |
+
figure=px.scatter(
|
304 |
+
iris,
|
305 |
+
x="petal_length",
|
306 |
+
y="sepal_width",
|
307 |
+
color="species",
|
308 |
+
),
|
309 |
+
),
|
310 |
+
],
|
311 |
+
controls=[
|
312 |
+
vm.Filter(column="species"),
|
313 |
+
vm.Filter(
|
314 |
+
column="petal_length",
|
315 |
+
targets=["scatter_chart2"],
|
316 |
+
selector=vm.RangeSlider(),
|
317 |
+
),
|
318 |
+
],
|
319 |
+
)
|
320 |
+
|
321 |
+
parameters = vm.Page(
|
322 |
+
title="Parameters",
|
323 |
+
components=[
|
324 |
+
vm.Graph(
|
325 |
+
id="scatter_chart_pm",
|
326 |
+
figure=px.scatter(
|
327 |
+
iris,
|
328 |
+
x="sepal_width",
|
329 |
+
y="sepal_length",
|
330 |
+
color="species",
|
331 |
+
size="petal_length",
|
332 |
+
color_discrete_map={"setosa": "#00b4ff", "versicolor": "#ff9222"},
|
333 |
+
),
|
334 |
+
),
|
335 |
+
vm.Graph(
|
336 |
+
id="bar_chart_pm",
|
337 |
+
figure=px.bar(
|
338 |
+
iris,
|
339 |
+
x="sepal_width",
|
340 |
+
y="sepal_length",
|
341 |
+
color="species",
|
342 |
+
color_discrete_map={"setosa": "#00b4ff", "versicolor": "#ff9222"},
|
343 |
+
),
|
344 |
+
),
|
345 |
+
],
|
346 |
+
controls=[
|
347 |
+
vm.Parameter(
|
348 |
+
targets=["scatter_chart_pm.color_discrete_map.virginica", "bar_chart_pm.color_discrete_map.virginica"],
|
349 |
+
selector=vm.Dropdown(options=["#ff5267", "#3949ab"], multi=False, value="#3949ab"),
|
350 |
+
)
|
351 |
+
],
|
352 |
+
)
|
353 |
+
|
354 |
+
selectors = vm.Page(
|
355 |
+
title="Selectors",
|
356 |
+
layout=vm.Layout(grid=[[0], [1], [1], [1], [2], [2], [2], [3], [3], [3]], row_min_height="170px", row_gap="24px"),
|
357 |
+
components=[
|
358 |
+
vm.Card(
|
359 |
+
text="""
|
360 |
+
A selector can be used within the **Parameter** or **Filter** component to allow the user to select a value.
|
361 |
+
|
362 |
+
The following selectors are available:
|
363 |
+
* Dropdown (**categorical** multi and single option selector)
|
364 |
+
* Checklist (**categorical** multi option selector only)
|
365 |
+
* RadioItems (**categorical** single option selector only)
|
366 |
+
* RangeSlider (**numerical** multi option selector only)
|
367 |
+
* Slider (**numerical** single option selector only)
|
368 |
+
* DatePicker(**temporal** multi and single option selector)
|
369 |
+
|
370 |
+
"""
|
371 |
+
),
|
372 |
+
vm.Table(
|
373 |
+
id="table-gapminder",
|
374 |
+
figure=dash_data_table(data_frame=gapminder_2007, page_size=10),
|
375 |
+
title="Gapminder Data",
|
376 |
+
),
|
377 |
+
vm.Table(id="table-tips", figure=dash_data_table(data_frame=tips, page_size=10), title="Tips Data"),
|
378 |
+
vm.Graph(
|
379 |
+
id="graph-stocks",
|
380 |
+
figure=px.line(stocks, x="date", y="GOOG", title="Stocks Data"),
|
381 |
+
),
|
382 |
+
],
|
383 |
+
controls=[
|
384 |
+
vm.Filter(
|
385 |
+
targets=["table-gapminder"],
|
386 |
+
column="lifeExp",
|
387 |
+
selector=vm.RangeSlider(title="Range Slider (Gapminder - lifeExp)", step=1, marks=None),
|
388 |
+
),
|
389 |
+
vm.Filter(
|
390 |
+
targets=["table-gapminder"],
|
391 |
+
column="continent",
|
392 |
+
selector=vm.Checklist(title="Checklist (Gapminder - continent)"),
|
393 |
+
),
|
394 |
+
vm.Filter(
|
395 |
+
targets=["table-gapminder"],
|
396 |
+
column="country",
|
397 |
+
selector=vm.Dropdown(title="Dropdown (Gapminder - country)"),
|
398 |
+
),
|
399 |
+
vm.Filter(
|
400 |
+
targets=["table-tips"],
|
401 |
+
column="day",
|
402 |
+
selector=vm.Dropdown(title="Dropdown (Tips - day)", multi=False, value="Sat"),
|
403 |
+
),
|
404 |
+
vm.Filter(
|
405 |
+
targets=["table-tips"],
|
406 |
+
column="sex",
|
407 |
+
selector=vm.RadioItems(title="Radio Items (Tips - sex)"),
|
408 |
+
),
|
409 |
+
vm.Filter(
|
410 |
+
targets=["table-tips"],
|
411 |
+
column="size",
|
412 |
+
selector=vm.Slider(title="Slider (Tips - size)", step=1, value=2),
|
413 |
+
),
|
414 |
+
vm.Filter(targets=["graph-stocks"], column="date", selector=vm.DatePicker(title="Date Picker (Stocks - date)")),
|
415 |
+
],
|
416 |
+
)
|
417 |
+
|
418 |
+
# ACTIONS ---------------------------------------------------------------------
|
419 |
+
export_data_action = vm.Page(
|
420 |
+
title="Export data",
|
421 |
+
components=[
|
422 |
+
vm.Graph(figure=px.scatter(iris, x="petal_length", y="sepal_length", color="species")),
|
423 |
+
vm.Graph(figure=px.histogram(iris, x="petal_length", color="species")),
|
424 |
+
vm.Button(text="Export data", actions=[vm.Action(function=export_data())]),
|
425 |
+
],
|
426 |
+
controls=[vm.Filter(column="species")],
|
427 |
+
)
|
428 |
+
|
429 |
+
|
430 |
+
chart_interaction = vm.Page(
|
431 |
+
title="Chart interaction",
|
432 |
+
components=[
|
433 |
+
vm.Graph(
|
434 |
+
figure=px.box(
|
435 |
+
gapminder_2007,
|
436 |
+
x="continent",
|
437 |
+
y="lifeExp",
|
438 |
+
color="continent",
|
439 |
+
custom_data=["continent"],
|
440 |
+
),
|
441 |
+
actions=[vm.Action(function=filter_interaction(targets=["scatter_relation_2007"]))],
|
442 |
+
),
|
443 |
+
vm.Graph(
|
444 |
+
id="scatter_relation_2007",
|
445 |
+
figure=px.scatter(
|
446 |
+
gapminder_2007,
|
447 |
+
x="gdpPercap",
|
448 |
+
y="lifeExp",
|
449 |
+
size="pop",
|
450 |
+
color="continent",
|
451 |
+
),
|
452 |
+
),
|
453 |
+
],
|
454 |
+
)
|
455 |
+
|
456 |
+
|
457 |
+
# CUSTOM CHARTS ------------------------------------------------------------------
|
458 |
+
@capture("graph")
|
459 |
+
def scatter_with_line(data_frame, x, y, hline=None, title=None):
|
460 |
+
"""Custom scatter chart based on px."""
|
461 |
+
fig = px.scatter(data_frame=data_frame, x=x, y=y, title=title)
|
462 |
+
fig.add_hline(y=hline, line_color="orange")
|
463 |
+
return fig
|
464 |
+
|
465 |
+
|
466 |
+
@capture("graph")
|
467 |
+
def waterfall(data_frame, measure, x, y, text, title=None): # noqa: PLR0913
|
468 |
+
"""Custom waterfall chart based on go."""
|
469 |
+
fig = go.Figure()
|
470 |
+
fig.add_traces(
|
471 |
+
go.Waterfall(
|
472 |
+
measure=data_frame[measure],
|
473 |
+
x=data_frame[x],
|
474 |
+
y=data_frame[y],
|
475 |
+
text=data_frame[text],
|
476 |
+
decreasing={"marker": {"color": "#ff5267"}},
|
477 |
+
increasing={"marker": {"color": "#08bdba"}},
|
478 |
+
totals={"marker": {"color": "#00b4ff"}},
|
479 |
+
)
|
480 |
+
)
|
481 |
+
fig.update_layout(title=title)
|
482 |
+
return fig
|
483 |
+
|
484 |
+
|
485 |
+
custom_charts = vm.Page(
|
486 |
+
title="Custom Charts",
|
487 |
+
components=[
|
488 |
+
vm.Graph(
|
489 |
+
id="custom_scatter",
|
490 |
+
figure=scatter_with_line(
|
491 |
+
x="sepal_length",
|
492 |
+
y="sepal_width",
|
493 |
+
hline=3.5,
|
494 |
+
data_frame=iris,
|
495 |
+
title="Custom px chart",
|
496 |
+
),
|
497 |
+
),
|
498 |
+
vm.Graph(
|
499 |
+
id="custom_waterfall",
|
500 |
+
figure=waterfall(
|
501 |
+
data_frame=waterfall_df,
|
502 |
+
measure="measure",
|
503 |
+
x="x",
|
504 |
+
y="y",
|
505 |
+
text="text",
|
506 |
+
title="Custom go chart",
|
507 |
+
),
|
508 |
+
),
|
509 |
+
],
|
510 |
+
controls=[
|
511 |
+
vm.Filter(column="petal_width", targets=["custom_scatter"]),
|
512 |
+
vm.Filter(
|
513 |
+
column="x",
|
514 |
+
targets=["custom_waterfall"],
|
515 |
+
selector=vm.Dropdown(title="Financial categories", multi=True),
|
516 |
+
),
|
517 |
+
],
|
518 |
+
)
|
519 |
+
|
520 |
+
|
521 |
+
# CUSTOM TABLE ------------------------------------------------------------------
|
522 |
+
@capture("table")
|
523 |
+
def my_custom_table(data_frame=None, chosen_columns: Optional[List[str]] = None):
|
524 |
+
"""Custom table with added logic to filter on chosen columns."""
|
525 |
+
columns = [{"name": i, "id": i} for i in chosen_columns]
|
526 |
+
defaults = {
|
527 |
+
"style_as_list_view": True,
|
528 |
+
"style_data": {"border_bottom": "1px solid var(--border-subtle-alpha-01)", "height": "40px"},
|
529 |
+
"style_header": {
|
530 |
+
"border_bottom": "1px solid var(--state-overlays-selected-hover)",
|
531 |
+
"border_top": "1px solid var(--main-container-bg-color)",
|
532 |
+
"height": "32px",
|
533 |
+
},
|
534 |
+
}
|
535 |
+
return dash_table.DataTable(data=data_frame.to_dict("records"), columns=columns, **defaults)
|
536 |
+
|
537 |
+
|
538 |
+
custom_tables = vm.Page(
|
539 |
+
title="Custom Tables",
|
540 |
+
components=[
|
541 |
+
vm.Table(
|
542 |
+
id="custom_table",
|
543 |
+
title="Custom Dash DataTable",
|
544 |
+
figure=my_custom_table(
|
545 |
+
data_frame=gapminder_2007,
|
546 |
+
chosen_columns=["country", "continent", "lifeExp", "pop", "gdpPercap"],
|
547 |
+
),
|
548 |
+
)
|
549 |
+
],
|
550 |
+
controls=[
|
551 |
+
vm.Parameter(
|
552 |
+
targets=["custom_table.chosen_columns"],
|
553 |
+
selector=vm.Dropdown(
|
554 |
+
title="Choose columns",
|
555 |
+
options=gapminder_2007.columns.to_list(),
|
556 |
+
multi=True,
|
557 |
+
),
|
558 |
+
)
|
559 |
+
],
|
560 |
+
)
|
561 |
+
|
562 |
+
|
563 |
+
# CUSTOM COMPONENTS -------------------------------------------------------------
|
564 |
+
# 1. Extend existing components
|
565 |
+
class TooltipNonCrossRangeSlider(vm.RangeSlider):
|
566 |
+
"""Custom numeric multi-selector `TooltipNonCrossRangeSlider`."""
|
567 |
+
|
568 |
+
type: Literal["other_range_slider"] = "other_range_slider"
|
569 |
+
|
570 |
+
def build(self):
|
571 |
+
"""Extend existing component by calling the super build and update properties."""
|
572 |
+
range_slider_build_obj = super().build()
|
573 |
+
range_slider_build_obj[self.id].allowCross = False
|
574 |
+
range_slider_build_obj[self.id].tooltip = {"always_visible": True, "placement": "bottom"}
|
575 |
+
return range_slider_build_obj
|
576 |
+
|
577 |
+
|
578 |
+
vm.Filter.add_type("selector", TooltipNonCrossRangeSlider)
|
579 |
+
|
580 |
+
|
581 |
+
# 2. Create new custom component
|
582 |
+
class Jumbotron(vm.VizroBaseModel):
|
583 |
+
"""New custom component `Jumbotron`."""
|
584 |
+
|
585 |
+
type: Literal["jumbotron"] = "jumbotron"
|
586 |
+
title: str
|
587 |
+
subtitle: str
|
588 |
+
text: str
|
589 |
+
|
590 |
+
def build(self):
|
591 |
+
"""Build the new component based on Dash components."""
|
592 |
+
return html.Div([html.H2(self.title), html.H3(self.subtitle), html.P(self.text)])
|
593 |
+
|
594 |
+
|
595 |
+
vm.Page.add_type("components", Jumbotron)
|
596 |
+
|
597 |
+
custom_components = vm.Page(
|
598 |
+
title="Custom Components",
|
599 |
+
components=[
|
600 |
+
Jumbotron(
|
601 |
+
title="Custom component based on new creation",
|
602 |
+
subtitle="This is a subtitle to summarize some content.",
|
603 |
+
text="This is the main body of text of the Jumbotron.",
|
604 |
+
),
|
605 |
+
vm.Graph(
|
606 |
+
id="for_custom_chart",
|
607 |
+
figure=px.scatter(
|
608 |
+
iris,
|
609 |
+
title="Iris Dataset",
|
610 |
+
x="sepal_length",
|
611 |
+
y="petal_width",
|
612 |
+
color="sepal_width",
|
613 |
+
),
|
614 |
+
),
|
615 |
+
],
|
616 |
+
controls=[
|
617 |
+
vm.Filter(
|
618 |
+
column="sepal_length",
|
619 |
+
targets=["for_custom_chart"],
|
620 |
+
selector=TooltipNonCrossRangeSlider(title="Custom component based on extension"),
|
621 |
+
)
|
622 |
+
],
|
623 |
+
)
|
624 |
+
|
625 |
+
|
626 |
+
# CUSTOM ACTIONS ---------------------------------------------------------------
|
627 |
+
@capture("action")
|
628 |
+
def my_custom_action(t: int):
|
629 |
+
"""Custom action."""
|
630 |
+
sleep(t)
|
631 |
+
|
632 |
+
|
633 |
+
custom_actions = vm.Page(
|
634 |
+
title="Custom Actions",
|
635 |
+
components=[
|
636 |
+
vm.Graph(
|
637 |
+
figure=px.scatter(
|
638 |
+
iris,
|
639 |
+
x="sepal_length",
|
640 |
+
y="petal_width",
|
641 |
+
color="species",
|
642 |
+
)
|
643 |
+
),
|
644 |
+
vm.Button(
|
645 |
+
text="Export data",
|
646 |
+
actions=[
|
647 |
+
vm.Action(function=export_data()),
|
648 |
+
vm.Action(function=my_custom_action(t=2)),
|
649 |
+
vm.Action(function=export_data(file_format="xlsx")),
|
650 |
+
],
|
651 |
+
),
|
652 |
+
],
|
653 |
+
controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))],
|
654 |
+
)
|
655 |
+
|
656 |
+
# DASHBOARD -------------------------------------------------------------------
|
657 |
+
components = [graphs, ag_grid, table, cards, button, containers, tabs]
|
658 |
+
controls = [filters, parameters, selectors]
|
659 |
+
actions = [export_data_action, chart_interaction]
|
660 |
+
extensions = [custom_charts, custom_tables, custom_components, custom_actions]
|
661 |
+
|
662 |
+
dashboard = vm.Dashboard(
|
663 |
+
title="Vizro Features",
|
664 |
+
pages=[home, *components, *controls, *actions, *extensions],
|
665 |
+
navigation=vm.Navigation(
|
666 |
+
nav_selector=vm.NavBar(
|
667 |
+
items=[
|
668 |
+
vm.NavLink(label="Homepage", pages=["Homepage"], icon="Home"),
|
669 |
+
vm.NavLink(
|
670 |
+
label="Features",
|
671 |
+
pages={
|
672 |
+
"Components": ["Graphs", "AG Grid", "Table", "Cards", "Button", "Containers", "Tabs"],
|
673 |
+
"Controls": ["Filters", "Parameters", "Selectors"],
|
674 |
+
"Actions": ["Export data", "Chart interaction"],
|
675 |
+
"Extensions": ["Custom Charts", "Custom Tables", "Custom Components", "Custom Actions"],
|
676 |
+
},
|
677 |
+
icon="Library Add",
|
678 |
+
),
|
679 |
+
]
|
680 |
+
)
|
681 |
+
),
|
682 |
+
)
|
683 |
+
|
684 |
+
if __name__ == "__main__":
|
685 |
+
Vizro().build(dashboard).run()
|
assets/css/custom.css
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
#page-header {
|
2 |
+
padding-left: 8px;
|
3 |
+
}
|
assets/favicon.ico
ADDED
assets/images/app.svg
ADDED
assets/images/icons/download.svg
ADDED
assets/images/icons/filters.svg
ADDED
assets/images/icons/line-chart.svg
ADDED
assets/images/icons/use-case.svg
ADDED
assets/images/logo.svg
ADDED