-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Alexandre Sajus
committed
Dec 11, 2024
1 parent
b3cb352
commit 5aa1d51
Showing
17 changed files
with
530 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
title: Creating a Sales Dashboard | ||
category: fundamentals | ||
data-keywords: gui vizelement chart navbar table layout part menu state multi-page callback | ||
short-description: Understand basic knowledge of Taipy by creating a multi-page sales dashboard. | ||
order: 1.5 | ||
img: sales_dashboard/images/thumbnail.png | ||
--- | ||
|
||
!!! note "Supported Python versions" | ||
Taipy requires **Python 3.9** or newer. | ||
|
||
This tutorial focuses on creating a simple sales dashboard application. You'll learn about visual elements, | ||
interaction, styling, and multi-page applications. | ||
|
||
![Final Application](images/final_app.png){width=90% .tp-image-border} | ||
|
||
This tutorial is also available in video format: | ||
|
||
<p align="center"> | ||
<a href="https://youtu.be/4F-266YnTkM" target="_blank"> | ||
<img src="images/yt-thumbnail.png" alt="Youtube Tutorial" width="50%"/> | ||
</a> | ||
</p> | ||
|
||
### Installation | ||
|
||
Ensure you have Python 3.9 or newer, then install Taipy and Plotly: | ||
|
||
```bash | ||
pip install taipy plotly | ||
``` | ||
|
||
!!! info | ||
Use `pip install taipy` for the latest stable version. Need help with pip? Check out | ||
the [installation guide](http://docs.python-guide.org/en/latest/starting/installation/). | ||
|
||
The dataset used in this tutorial is the | ||
[SuperStore Sales dataset](https://www.kaggle.com/datasets/rohitsahoo/sales-forecasting) | ||
available [here](https://github.com/AlexandreSajus/taipy-course/blob/main/data.csv). | ||
|
||
## Tutorial Steps | ||
|
||
1. [Visual Elements](step_01/step_01.md) | ||
2. [Styling](step_02/step_02.md) | ||
3. [Charts](step_03/step_03.md) | ||
4. [Multipage](step_04/step_04.md) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 115 additions & 0 deletions
115
docs/tutorials/articles/sales_dashboard/step_01/step_01.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
--- | ||
hide: | ||
- toc | ||
--- | ||
|
||
The full code for this step is available | ||
[here](https://github.com/AlexandreSajus/taipy-course/blob/main/2_visual_elements/main.py) | ||
|
||
Let's start by creating a simple page with 3 components: a selector to select a category of items, | ||
a bar chart which displays the sales of the top 10 countries for this category and | ||
a table which displays data for the selected category | ||
|
||
![Step 1 Application](images/simple_app.png){ width=90% : .tp-image-border } | ||
|
||
Let's start by importing the necessary libraries: | ||
|
||
```python | ||
from taipy.gui import Gui | ||
import taipy.gui.builder as tgb | ||
import pandas as pd | ||
``` | ||
|
||
We can now start creating the page. We will first add a [selector](../../../../refmans/gui/viselements/generic/selector.md). | ||
|
||
```python | ||
with tgb.Page() as page: | ||
tgb.selector(value="{selected_category}", lov="{categories}", on_change=change_category) | ||
``` | ||
|
||
Taipy [visual elements](../../../../refmans/gui/viselements/index.md) take many properties. | ||
Note that dynamic properties use a quote and brackets syntax. We use `value="{selected_category}"` | ||
to signal to Taipy that `selected_category` should change when the user uses the selector. | ||
Likewise, if `categories` changes, the selector will get updated with the new values. | ||
|
||
Here, selector needs an associated string variable which will change when a user selects a value, | ||
a list of values (lov) to choose from, and a callback function to call when the value changes. | ||
We can define them above: | ||
|
||
```python | ||
data = pd.read_csv("data.csv") | ||
selected_category = "Furniture" | ||
categories = list(data["Category"].unique()) | ||
|
||
def change_category(state): | ||
# Do nothing for now, we will implement this later | ||
return None | ||
``` | ||
|
||
We can now add a chart to display the sales of the top 10 countries for the selected category. | ||
|
||
```python | ||
tgb.chart( | ||
data="{chart_data}", | ||
x="State", | ||
y="Sales", | ||
type="bar", | ||
layout="{layout}", | ||
) | ||
``` | ||
|
||
Taipy charts have a specific syntax described [here](../../../../refmans/gui/viselements/generic/chart.md). You | ||
can also directly embed Plotly charts using the `figure` property as we will do in [Step 3](../step_03/step_03.md). | ||
|
||
Here we need to provide a Pandas Dataframe with the data to display, the x and y columns to use, the type of chart, | ||
and a layout dictionary with additional properties. | ||
|
||
```python | ||
chart_data = ( | ||
data.groupby("State")["Sales"] | ||
.sum() | ||
.sort_values(ascending=False) | ||
.head(10) | ||
.reset_index() | ||
) | ||
|
||
layout = {"yaxis": {"title": "Revenue (USD)"}, "title": "Sales by State"} | ||
``` | ||
|
||
Lastly, we can add a table to display the data for the selected category. | ||
|
||
```python | ||
tgb.table(data="{data}") | ||
``` | ||
|
||
We can now run the application using: | ||
|
||
```python | ||
Gui(page=page).run(title="Sales", dark_mode=False, debug=True) | ||
``` | ||
|
||
`debug=True` will display a stack trace of the errors if any occur. | ||
You can also set `use_reloader=True` to automatically reload the page | ||
when you save changes to the code and `port=XXXX` to change the server port. | ||
|
||
The application runs but has no interaction. We need to code the callback function | ||
to update the chart and table when the user selects a category. | ||
|
||
```python | ||
def change_category(state): | ||
state.data = data[data["Category"] == state.selected_category] | ||
state.chart_data = ( | ||
state.data.groupby("State")["Sales"] | ||
.sum() | ||
.sort_values(ascending=False) | ||
.head(10) | ||
.reset_index() | ||
) | ||
state.layout = { | ||
"yaxis": {"title": "Revenue (USD)"}, | ||
"title": f"Sales by State for {state.selected_category}", | ||
} | ||
``` | ||
|
||
Taipy uses a `state` object to store the variables per client. | ||
The syntax to update a variable will always be `state.variable = new_value`. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+85.1 KB
docs/tutorials/articles/sales_dashboard/step_02/images/styling_app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
198 changes: 198 additions & 0 deletions
198
docs/tutorials/articles/sales_dashboard/step_02/step_02.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
--- | ||
hide: | ||
- toc | ||
--- | ||
|
||
The full code for this step is available | ||
[here](https://github.com/AlexandreSajus/taipy-course/tree/main/3_styling) | ||
|
||
This step will be about styling the application. We will add more filters, layout the visual element and | ||
regroup them in parts. | ||
|
||
![Styling Application](images/styling_app.png){ width=90% : .tp-image-border } | ||
|
||
We can still use the same code as the previous step, but let's recreate the page from scratch: | ||
|
||
```python | ||
with tgb.Page() as page: | ||
with tgb.part(class_name="container"): | ||
tgb.text("# Sales by **State**", mode="md") | ||
``` | ||
|
||
[Part](../../../../refmans/gui/viselements/generic/part.md) allows you to group and style visual elements together. | ||
Here, the [container](../../../../userman/gui/styling/stylekit.md) class is a predefined style | ||
that will limit the width of visual elements contained in the part. | ||
|
||
[Text](../../../../refmans/gui/viselements/generic/text.md) is a simple text visual element. Here we use the | ||
Markdown (md) mode to display a title and make the word "State". We can also color bold text in orange | ||
by using CSS. Create a new CSS file with the same name as the Python file and add the following code: | ||
|
||
```css | ||
strong, | ||
b { | ||
font-weight: bold; | ||
color: var(--color-primary); | ||
} | ||
``` | ||
|
||
Let's now add a new container for the filters: | ||
|
||
```python | ||
with tgb.part(class_name="card"): | ||
with tgb.layout(columns="1 2 1"): | ||
with tgb.part(): | ||
tgb.text("Filter **From**", mode="md") | ||
with tgb.part(): | ||
tgb.text("Filter Product **Category**", mode="md") | ||
with tgb.part(class_name="text-center"): | ||
tgb.button( | ||
"Apply", | ||
) | ||
``` | ||
|
||
[Card](../../../../userman/gui/styling/stylekit.md) is a predefined style that will regroup visual elements in | ||
a white box. [layout](../../../../refmans/gui/viselements/generic/layout.md) allows you to create columns | ||
for visual elements. Here we create 3 columns with a ratio of 1:2:1, the second column will be twice as wide as the | ||
first and last columns. The contents of each column then needs to be separated in parts. | ||
|
||
![Layout](images/layout.png){ width=90% : .tp-image-border } | ||
|
||
We can now add [date selectors](../../../../refmans/gui/viselements/generic/date.md), | ||
[selectors](../../../../refmans/gui/viselements/generic/selector.md) and a | ||
[button](../../../../refmans/gui/viselements/generic/button.md) to apply the filters: | ||
|
||
```python | ||
with tgb.part(class_name="card"): | ||
with tgb.layout(columns="1 2 1"): | ||
with tgb.part(): | ||
tgb.text("Filter **From**", mode="md") | ||
tgb.date("{start_date}") | ||
tgb.text("To") | ||
tgb.date("{end_date}") | ||
with tgb.part(): | ||
tgb.text("Filter Product **Category**", mode="md") | ||
tgb.selector( | ||
value="{selected_category}", | ||
lov="{categories}", | ||
on_change=change_category, | ||
dropdown=True, | ||
) | ||
tgb.text("Filter Product **Subcategory**", mode="md") | ||
tgb.selector( | ||
value="{selected_subcategory}", | ||
lov="{subcategories}", | ||
dropdown=True, | ||
) | ||
with tgb.part(class_name="text-center"): | ||
tgb.button( | ||
"Apply", | ||
class_name="plain apply_button", | ||
on_action=apply_changes, | ||
) | ||
``` | ||
|
||
You'll notice we converted our selectors to dropdowns by setting the `dropdown` property to `True`. | ||
We also applied styling to the button: `plain` is a predefined style that colors the button in orange. | ||
Predefined styles are available in visual elements documentation. | ||
Check out the styling part of [button](../../../../refmans/gui/viselements/generic/button.md/). | ||
`apply_button` is a custom style that we can add using our CSS file: | ||
|
||
```css | ||
.apply_button { | ||
margin-top: 158px; | ||
} | ||
``` | ||
|
||
This will add a margin to the top of the button to align it with the filters. | ||
We can also add properties to all Taipy buttons by applying properties to the `taipy-button` class | ||
(You can find these class names by inspecting the page on a visual element) | ||
|
||
```css | ||
.taipy-button { | ||
width: 60% | ||
} | ||
``` | ||
|
||
![Filters](images/filters.png){ width=90% : .tp-image-border } | ||
|
||
We can now add the chart and the table: | ||
|
||
```python | ||
tgb.html("br") | ||
tgb.chart( | ||
data="{chart_data}", | ||
x="State", | ||
y="Sales", | ||
type="bar", | ||
layout="{layout}", | ||
) | ||
tgb.html("br") | ||
tgb.table(data="{data}") | ||
|
||
Gui(page=page).run(title="Sales", dark_mode=False, debug=True) | ||
|
||
``` | ||
|
||
We use `tgb.html("br")` to add a line break and create space between elements. | ||
|
||
The last thing we need is to initialize the new variables and create the callback | ||
function to apply the filter: | ||
|
||
```python | ||
data = pd.read_csv("data.csv") | ||
chart_data = ( | ||
data.groupby("State")["Sales"] | ||
.sum() | ||
.sort_values(ascending=False) | ||
.head(10) | ||
.reset_index() | ||
) | ||
|
||
start_date = "2015-01-01" | ||
start_date = pd.to_datetime(start_date) | ||
end_date = "2018-12-31" | ||
end_date = pd.to_datetime(end_date) | ||
|
||
categories = list(data["Category"].unique()) | ||
selected_category = "Furniture" | ||
|
||
selected_subcategory = "Bookcases" | ||
subcategories = list( | ||
data[data["Category"] == selected_category]["Sub-Category"].unique() | ||
) | ||
|
||
layout = {"yaxis": {"title": "Revenue (USD)"}, "title": "Sales by State"} | ||
|
||
|
||
def change_category(state): | ||
state.subcategories = list( | ||
data[data["Category"] == state.selected_category]["Sub-Category"].unique() | ||
) | ||
state.selected_subcategory = state.subcategories[0] | ||
|
||
|
||
def apply_changes(state): | ||
state.data = data[ | ||
( | ||
pd.to_datetime(data["Order Date"], format="%d/%m/%Y") | ||
>= pd.to_datetime(state.start_date) | ||
) | ||
& ( | ||
pd.to_datetime(data["Order Date"], format="%d/%m/%Y") | ||
<= pd.to_datetime(state.end_date) | ||
) | ||
] | ||
state.data = state.data[state.data["Category"] == state.selected_category] | ||
state.data = state.data[state.data["Sub-Category"] == state.selected_subcategory] | ||
state.chart_data = ( | ||
state.data.groupby("State")["Sales"] | ||
.sum() | ||
.sort_values(ascending=False) | ||
.head(10) | ||
.reset_index() | ||
) | ||
state.layout = { | ||
"yaxis": {"title": "Revenue (USD)"}, | ||
"title": f"Sales by State for {state.selected_category} - {state.selected_subcategory}", | ||
} | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.