diff --git a/docs/tutorials/articles/sales_dashboard/images/final_app.png b/docs/tutorials/articles/sales_dashboard/images/final_app.png new file mode 100644 index 000000000..536c586a6 Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/images/final_app.png differ diff --git a/docs/tutorials/articles/sales_dashboard/images/thumbnail.png b/docs/tutorials/articles/sales_dashboard/images/thumbnail.png new file mode 100644 index 000000000..d6ca7502e Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/images/thumbnail.png differ diff --git a/docs/tutorials/articles/sales_dashboard/images/yt-thumbnail.png b/docs/tutorials/articles/sales_dashboard/images/yt-thumbnail.png new file mode 100644 index 000000000..e17c0778a Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/images/yt-thumbnail.png differ diff --git a/docs/tutorials/articles/sales_dashboard/index.md b/docs/tutorials/articles/sales_dashboard/index.md new file mode 100644 index 000000000..0bc162b12 --- /dev/null +++ b/docs/tutorials/articles/sales_dashboard/index.md @@ -0,0 +1,56 @@ +--- +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} + +### Why Taipy? + +- **Speed:** Quickly develop robust applications. +- **Simplicity:** Easy management of variables and events. +- **Visualization:** Intuitive and clear visual elements. + +Each step in this **Tutorial** builds on the previous one. By the end, you'll be ready to +create your own Taipy applications. + +This tutorial is also available in video format: + +
+ + + +
+ +### 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/Avaiga/taipy-course-gui/blob/develop/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) diff --git a/docs/tutorials/articles/sales_dashboard/step_01/images/simple_app.png b/docs/tutorials/articles/sales_dashboard/step_01/images/simple_app.png new file mode 100644 index 000000000..fac2d939b Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/step_01/images/simple_app.png differ diff --git a/docs/tutorials/articles/sales_dashboard/step_01/step_01.md b/docs/tutorials/articles/sales_dashboard/step_01/step_01.md new file mode 100644 index 000000000..fe4a37efa --- /dev/null +++ b/docs/tutorials/articles/sales_dashboard/step_01/step_01.md @@ -0,0 +1,163 @@ +--- +hide: + - toc +--- + +The full code for this step is available +[here](https://github.com/Avaiga/taipy-course-gui/blob/develop/2_visual_elements/main.py){: .tp-btn target='blank' } + +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" + ```python + from taipy.gui import Gui + import taipy.gui.builder as tgb + import pandas as pd + ``` +=== "Markdown" + ```python + from taipy.gui import Gui + import pandas as pd + ``` + +We can now start creating the page. We will first add a [selector](../../../../refmans/gui/viselements/generic/selector.md). + +=== "Python" + ```python + with tgb.Page() as page: + tgb.selector(value="{selected_category}", lov="{categories}", on_change=change_category) + ``` +=== "Markdown" + ```python + page = """ + <|{selected_category}|selector|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" + ```python + tgb.chart( + data="{chart_data}", + x="State", + y="Sales", + type="bar", + layout="{layout}", + ) + ``` +=== "Markdown" + ``` + <|{chart_data}|chart|x=State|y=Sales|type=bar|layout={layout}|> + ``` + +Taipy charts have many properties. You can create multiple traces, add styling, change the type of chart, etc. + +=== "Python" + ```python + data = {"x_col": [0, 1, 2], "y_col1": [4, 1, 2], "y_col_2": [3, 1, 2]} + with tgb.Page() as page: + tgb.chart("{data}", x="x_col", y__1="y_col1", y__2="y_col_2", type__1="bar", color__2="red") + ``` +=== "Markdown" + ```python + data = {"x_col": [0, 1, 2], "y_col_1": [4, 2, 1], "y_col_2":[3, 1, 2]} + Gui("<|{data}|chart|x=x_col|y[1]=y_col_1|y[2]=y_col_2|type[1]=bar|color[2]=red|>").run() + ``` + + +You can check the syntax for charts [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" + ```python + tgb.table(data="{data}") + ``` +=== "Markdown" + ``` + <|{data}|table|> + ``` + +We can now run the application using: + +```python +if __name__ == "__main__": + 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}", + } +``` + +## State + +Taipy uses a `state` object to store the variables per client. +The syntax to update a variable will always be `state.variable = new_value`. + +State holds the value of all the variables used in the user interface for one specific connection. + +Modifying `state.data` will update data for one specific user, without modifying `state.data` for other users +or the global `data` variable. You can test this by opening the application in a separate incognito window. \ No newline at end of file diff --git a/docs/tutorials/articles/sales_dashboard/step_02/images/filters.png b/docs/tutorials/articles/sales_dashboard/step_02/images/filters.png new file mode 100644 index 000000000..1b19ffe00 Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/step_02/images/filters.png differ diff --git a/docs/tutorials/articles/sales_dashboard/step_02/images/layout.png b/docs/tutorials/articles/sales_dashboard/step_02/images/layout.png new file mode 100644 index 000000000..6d2397039 Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/step_02/images/layout.png differ diff --git a/docs/tutorials/articles/sales_dashboard/step_02/images/styling_app.png b/docs/tutorials/articles/sales_dashboard/step_02/images/styling_app.png new file mode 100644 index 000000000..b6f32eee7 Binary files /dev/null and b/docs/tutorials/articles/sales_dashboard/step_02/images/styling_app.png differ diff --git a/docs/tutorials/articles/sales_dashboard/step_02/step_02.md b/docs/tutorials/articles/sales_dashboard/step_02/step_02.md new file mode 100644 index 000000000..fe448dda1 --- /dev/null +++ b/docs/tutorials/articles/sales_dashboard/step_02/step_02.md @@ -0,0 +1,266 @@ +--- +hide: + - toc +--- + +The full code for this step is available +[here](https://github.com/Avaiga/taipy-course-gui/tree/develop/3_styling){: .tp-btn target='blank' } + +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" + ```python + with tgb.Page() as page: + with tgb.part(class_name="container"): + tgb.text("# Sales by **State**", mode="md") + ``` +=== "Markdown" + ```python + page = """ + <|part|class_name=container| + # Sales by **State** + |> + """ + ``` + +[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); +} +``` + +You can also connect visual elements to lambda functions. +For example, the following text visual element updates the displayed total sales when the data changes: + +```python +tgb.text(value=lambda data: f"Total Sales: {data['Sales'].sum():,.2f}") +``` + +Let's now add a new container for the filters: + +=== "Python" + ```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", + ) + ``` +=== "Markdown" + ``` + <|part|class_name=card| + <|layout|columns=1 2 1| + Filter **From** + + Filter Product **Category** + + <|part|class_name=text-center| + <|Apply|button|> + |> + |> + |> + ``` + + +[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" + ```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, + ) + ``` +=== "Markdown" + ``` + <|part|class_name=card| + <|layout|columns=1 2 1| + Filter **From** + <|{start_date}|date|> + To + <|{end_date}|date|> + + Filter Product **Category** + <|{selected_category}|selector|lov={categories}|on_change=change_category|dropdown=True|> + Filter Product **Subcategory** + <|{selected_subcategory}|selector|lov={subcategories}|dropdown=True|> + + <|Apply|button|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" + ```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) + ``` +=== "Markdown" + ```python + page = """ + ... +diff --git a/docs/tutorials/index.md_template b/docs/tutorials/index.md_template index 190b9e2ea..1c72fcd97 100644 --- a/docs/tutorials/index.md_template +++ b/docs/tutorials/index.md_template @@ -81,15 +81,15 @@ Learn how to build Taipy applications through tutorials! ## Favorites
- Understand basic knowledge of Taipy GUI creating of a multi-page NLP application. + Understand basic knowledge of Taipy by creating of a multi-page sales dashboard.