diff --git a/docs/tutorials/articles/callbacks/index.md b/docs/tutorials/articles/callbacks/index.md index b808d5b62..b9ae83092 100644 --- a/docs/tutorials/articles/callbacks/index.md +++ b/docs/tutorials/articles/callbacks/index.md @@ -49,30 +49,56 @@ Let’s demonstrate local callbacks with a small example. This simple app allows a user to select a temperature in degrees Fahrenheit and automatically convert it to degrees Celsius: -```python linenums="1" -from taipy.gui import Gui, Markdown +=== "Python" + ```python linenums="1" + from taipy.gui import Gui, Markdown + import taipy.gui.builder as tgb -def fahrenheit_to_celsius(fahrenheit): - return (fahrenheit - 32) * 5 / 9 + def fahrenheit_to_celsius(fahrenheit): + return (fahrenheit - 32) * 5 / 9 -def update_celsius(state): - state.celsius = fahrenheit_to_celsius(state.fahrenheit) + def update_celsius(state): + state.celsius = fahrenheit_to_celsius(state.fahrenheit) -if __name__=="__main__": - fahrenheit = 100 - celsius = fahrenheit_to_celsius(fahrenheit) + if __name__=="__main__": + fahrenheit = 100 + celsius = fahrenheit_to_celsius(fahrenheit) - md = Markdown(""" -# Local Callbacks -## Fahrenheit: -<|{fahrenheit}|number|on_change=update_celsius|> + with tgb.Page() as page: + tgb.text("# Local Callbacks", mode="md") + tgb.text("## Fahrenheit:", mode="md") + tgb.number("{fahrenheit}", on_change=update_celsius) -## Celsius: -<|{celsius}|number|active=False|> - """) + tgb.text("## Celsius:", mode="md") + tgb.number("{celsius}", active=False) + + Gui(page=page).run() + ``` +=== "Markdown" + ```python linenums="1" + from taipy.gui import Gui, Markdown - Gui(page=md).run() -``` + def fahrenheit_to_celsius(fahrenheit): + return (fahrenheit - 32) * 5 / 9 + + def update_celsius(state): + state.celsius = fahrenheit_to_celsius(state.fahrenheit) + + if __name__=="__main__": + fahrenheit = 100 + celsius = fahrenheit_to_celsius(fahrenheit) + + md = Markdown(""" + # Local Callbacks + ## Fahrenheit: + <|{fahrenheit}|number|on_change=update_celsius|> + + ## Celsius: + <|{celsius}|number|active=False|> + """) + + Gui(page=md).run() + ``` The relevant line here is line 12, where we defined a number control using the Taipy construct syntax. We will use this to select the temperature in degrees Fahrenheit which we wish to be @@ -104,41 +130,74 @@ the temperature in kelvin. Take a look at the updated code: -```python linenums="1" -from taipy.gui import Gui, Markdown +=== "Python" + ```python linenums="1" + from taipy.gui import Gui, Markdown + import taipy.gui.builder as tgb -def fahrenheit_to_celsius(fahrenheit): - return (fahrenheit - 32) * 5 / 9 + def fahrenheit_to_celsius(fahrenheit): + return (fahrenheit - 32) * 5 / 9 -def celsius_to_kelvin(celsius): - return celsius + 273.15 + def update_celsius(state): + state.celsius = fahrenheit_to_celsius(state.fahrenheit) -def update_celsius(state): - state.celsius = fahrenheit_to_celsius(state.fahrenheit) + def celsius_to_kelvin(celsius): + return celsius + 273.15 -def on_change(state, var_name, var_value): - if var_name == "celsius": - state.kelvin = celsius_to_kelvin(state.celsius) + if __name__=="__main__": + fahrenheit = 100 + celsius = fahrenheit_to_celsius(fahrenheit) + kelvin = celsius_to_kelvin(celsius) -if __name__=="__main__": - fahrenheit = 100 - celsius = fahrenheit_to_celsius(fahrenheit) - kelvin = celsius_to_kelvin(celsius) + with tgb.Page() as page: + tgb.text("# Local and Global Callbacks", mode="md") + tgb.text("## Fahrenheit:", mode="md") + tgb.number("{fahrenheit}", on_change=update_celsius) - md = Markdown(""" -# Local and Global Callbacks -## Fahrenheit: -<|{fahrenheit}|number|on_change=update_celsius|> + tgb.text("## Celsius:", mode="md") + tgb.number("{celsius}", active=False) -## Celsius: -<|{celsius}|number|active=False|> + tgb.text("## Kelvin:", mode="md") + tgb.number("{kelvin}", active=False) + + Gui(page=page).run() + ``` +=== "Markdown" + ```python linenums="1" + from taipy.gui import Gui, Markdown -## Kelvin: -<|{kelvin}|number|active=False|> - """) + def fahrenheit_to_celsius(fahrenheit): + return (fahrenheit - 32) * 5 / 9 - Gui(page=md).run(dark_mode=False) -``` + def celsius_to_kelvin(celsius): + return celsius + 273.15 + + def update_celsius(state): + state.celsius = fahrenheit_to_celsius(state.fahrenheit) + + def on_change(state, var_name, var_value): + if var_name == "celsius": + state.kelvin = celsius_to_kelvin(state.celsius) + + if __name__=="__main__": + fahrenheit = 100 + celsius = fahrenheit_to_celsius(fahrenheit) + kelvin = celsius_to_kelvin(celsius) + + md = Markdown(""" + # Local and Global Callbacks + ## Fahrenheit: + <|{fahrenheit}|number|on_change=update_celsius|> + + ## Celsius: + <|{celsius}|number|active=False|> + + ## Kelvin: + <|{kelvin}|number|active=False|> + """) + + Gui(page=md).run(dark_mode=False) + ``` On line 22, we added a new number control to our app, which is bound to the kelvin variable. The existing code we implemented in the previous section — which updates celsius when fahrenheit is @@ -188,34 +247,60 @@ global callback may be the right choice. Side-tracking a little from the focus of this article, it’s worth noting that this app never actually needed callbacks! We can update the code as follows: -```python -from taipy.gui import Gui, Markdown +=== "Python" + ```python linenums="1" + from taipy.gui import Gui, Markdown + import taipy.gui.builder as tgb -def fahrenheit_to_celsius(fahrenheit): - return (fahrenheit - 32) * 5 / 9 + def fahrenheit_to_celsius(fahrenheit): + return (fahrenheit - 32) * 5 / 9 -def celsius_to_kelvin(celsius): - return celsius + 273.15 + def update_celsius(state): + state.celsius = fahrenheit_to_celsius(state.fahrenheit) -if __name__=="__main__": - fahrenheit = 100 - celsius = fahrenheit_to_celsius(fahrenheit) - kelvin = celsius_to_kelvin(celsius) + if __name__=="__main__": + fahrenheit = 100 - md = Markdown(""" -# Global Callbacks -## Fahrenheit: -<|{fahrenheit}|number|> + with tgb.Page() as page: + tgb.text("# Global Callbacks", mode="md") + tgb.text("## Fahrenheit:", mode="md") + tgb.number("{fahrenheit}", on_change=update_celsius) -## Celsius: -<|{fahrenheit_to_celsius(fahrenheit)}|number|active=False|> + tgb.text("## Celsius:", mode="md") + tgb.number("{fahrenheit_to_celsius(fahrenheit)}", active=False) -## Kelvin: -<|{celsius_to_kelvin(fahrenheit_to_celsius(fahrenheit))}|number|active=False|> - """) + tgb.text("## Kelvin:", mode="md") + tgb.number("{celsius_to_kelvin(fahrenheit_to_celsius(fahrenheit))}", active=False) + + Gui(page=page).run() + ``` +=== "Markdown" + ```python + from taipy.gui import Gui, Markdown - Gui(page=md).run() -``` + def fahrenheit_to_celsius(fahrenheit): + return (fahrenheit - 32) * 5 / 9 + + def celsius_to_kelvin(celsius): + return celsius + 273.15 + + if __name__=="__main__": + fahrenheit = 100 + + md = Markdown(""" + # Global Callbacks + ## Fahrenheit: + <|{fahrenheit}|number|> + + ## Celsius: + <|{fahrenheit_to_celsius(fahrenheit)}|number|active=False|> + + ## Kelvin: + <|{celsius_to_kelvin(fahrenheit_to_celsius(fahrenheit))}|number|active=False|> + """) + + Gui(page=md).run() + ``` Without using any callbacks, we instead simply interpolate the expression to be evaluated into the curly braces for both the celsius and kelvin controls — much like an f-string! Since the diff --git a/docs/tutorials/articles/colab_with_ngrok/index.md b/docs/tutorials/articles/colab_with_ngrok/index.md index eca2ee7c7..3e19251ca 100644 --- a/docs/tutorials/articles/colab_with_ngrok/index.md +++ b/docs/tutorials/articles/colab_with_ngrok/index.md @@ -117,13 +117,16 @@ To address this issue, you can modify the *change_delay* parameter in one of the element. === "Python" - ```python - tgb.input("{text}", change_delay=800) - ``` -=== "Markdown" - ```python - <|{text}|input|change_delay=800|> - ``` + + ```python + tgb.input("{text}", change_delay=800) + ``` + +=== "Markdown" + + ```python + <|{text}|input|change_delay=800|> + ``` - **Globally**: To adjust the delay for all of Taipy's visual elements. @@ -147,43 +150,50 @@ re-executions required. You can learn more about this in the Here are the new cells to add: 1. Import Markdown: - ```python - from taipy.gui import Gui, Markdown - ``` + +```python +from taipy.gui import Gui, Markdown +``` 2. Create an empty new page: - ```python - new_page = Markdown("") - ``` + +```python +new_page = Markdown("") +``` 3. Set the page content: - ```python - new_page.set_content(page) - ``` + +```python +new_page.set_content(page) +``` 4. Update the `pages` definition: - ```python - pages = {"/":"<|toggle|theme|>\n
\n<|navbar|>\n
", - "line":new_page, - "text":page_file} - ``` + +```python +pages = {"/":"<|toggle|theme|>\n
\n<|navbar|>\n
", + "line":new_page, + "text":page_file} +``` ## Variable modification with `gui.reload` 1. Add this step: - ```python - gui=Gui(pages=pages) - ``` + +```python +gui = Gui(pages=pages) +``` 2. Update your `tp.run(gui)`: - ```python - gui.run() - ``` + +```python +gui.run() +``` 3. Add the `gui.reload` function: - ```python - gui.reload() - ``` + +```python +gui.reload() +``` After you've made your modifications, just rerun the cell where you made the changes and activate the reload function. Refresh your application page to view the updates you've made. diff --git a/docs/tutorials/articles/css_style_kit/index.md b/docs/tutorials/articles/css_style_kit/index.md index 592f57864..cd53466c1 100644 --- a/docs/tutorials/articles/css_style_kit/index.md +++ b/docs/tutorials/articles/css_style_kit/index.md @@ -35,14 +35,20 @@ You can easily add color or center it. Now, let's use it in our application: -```python -<|text-center| Taipy **App**{: .color-primary} |> +=== "Python" + ```python + with tgb.part("text-center"): + tgb.text("Taipy **App**", mode="md") # add a CSS class for the color + ``` +=== "Markdown" + ```python + <|text-center| Taipy **App**{: .color-primary} |> -or + or -Taipy **App**{: .color-primary} -{: .text-center} -``` + Taipy **App**{: .color-primary} + {: .text-center} + ``` Let’s apply it to our application. @@ -53,19 +59,31 @@ These can be used to make certain parts of your pages more noticeable or to cont For instance, you can use a container to add some space around your Markdown content. -```python -<|container| -... -|> -``` +=== "Python" + ```python + with tgb.part("container"): + ... + ``` +=== "Markdown" + ```python + <|container| + ... + |> + ``` This will create a card to put your Markdown/Visual elements in. -```python -<|card| -... -|> -``` +=== "Python" + ```python + with tgb.part("card"): + ... + ``` +=== "Markdown" + ```python + <|card| + ... + |> + ``` In this example, we put a container around the entire application, and we've also created a card for the parameters at the top. diff --git a/docs/tutorials/articles/databricks/index.md b/docs/tutorials/articles/databricks/index.md index 74cf1aaac..0cc404e81 100644 --- a/docs/tutorials/articles/databricks/index.md +++ b/docs/tutorials/articles/databricks/index.md @@ -36,7 +36,7 @@ jobs. Taipy's scenarios serve as a potent tool for orchestrating tasks and performing 'what-if' analysis (i.e. examining various versions of a business problem). -![Submitting a scenario in Taipy](images/submit_scenario.png){width=80% : .tp-image} +![Submitting a scenario in Taipy](images/submit_scenario.png){width=80% : .tp-image-border} # Scenarios and Databricks Integration @@ -199,7 +199,7 @@ retrieve the results from the Databricks job. In Databricks, you can monitor the job execution in real-time. Databricks provides logs and detailed information about the job's progress. -![Monitoring job execution in Databricks](images/databricks_job.png){width=80% : .tp-image} +![Monitoring job execution in Databricks](images/databricks_job.png){width=80% : .tp-image-border} # Databricks + Taipy @@ -212,4 +212,4 @@ within Taipy and benefit from: - Taipy's what-if analysis, supported by its scenario management, - Support for different end-user profiles, etc. -![Comparing scenario results in Taipy](images/compare_scenarios.png){width=80% : .tp-image} +![Comparing scenario results in Taipy](images/compare_scenarios.png){width=80% : .tp-image-border} diff --git a/docs/tutorials/articles/long_callbacks/index.md b/docs/tutorials/articles/long_callbacks/index.md index ccfd276ab..cf0d1b6de 100644 --- a/docs/tutorials/articles/long_callbacks/index.md +++ b/docs/tutorials/articles/long_callbacks/index.md @@ -27,15 +27,15 @@ Imagine a situation where a callback starts a duty that requires a lot of resour finish. To make this work, we can use a straightforward approach: ```python - from taipy.gui import State, invoke_long_callback, notify +from taipy.gui import State, invoke_long_callback, notify - def heavy_function(...): - # Do something that takes time... - ... +def heavy_function(...): + # Do something that takes time... + ... - def on_action(state): - notify(state, "info", "Heavy function started") - invoke_long_callback(state, heavy_function, [...heavy_function arguments...]) +def on_action(state): + notify(state, "info", "Heavy function started") + invoke_long_callback(state, heavy_function, [...heavy_function arguments...]) ``` In the previous example, the Taipy function `invoke_long_callback()^` manages the @@ -50,15 +50,15 @@ on the status of the ongoing process. Taipy offers a way to receive notification function completes, as shown below: ```python - def heavy_function_status(state, status): - if status: - notify(state, "success", "The heavy function has finished!") - else: - notify(state, "error", "The heavy function has failed") - - def on_action(state, id, action): - invoke_long_callback(state, heavy_function, [...heavy_function arguments...], - heavy_function_status) +def heavy_function_status(state, status): + if status: + notify(state, "success", "The heavy function has finished!") + else: + notify(state, "error", "The heavy function has failed") + +def on_action(state, id, action): + invoke_long_callback(state, heavy_function, [...heavy_function arguments...], + heavy_function_status) ``` In this example, we introduce the *heavy_function_status()* function, which the @@ -73,13 +73,13 @@ To update the `State` according to the returned value from *heavy_function()*, y `heavy_function_status()` as follows: ```python linenums="1" - def heavy_function_status(state, status, result): - if status: - notify(state, "success", "The heavy function has finished!") - # Actualize the State with the function result - state.result = result - else: - notify(state, "error", "The heavy function has failed") +def heavy_function_status(state, status, result): + if status: + notify(state, "success", "The heavy function has finished!") + # Actualize the State with the function result + state.result = result + else: + notify(state, "error", "The heavy function has failed") ``` We added a parameter called *result*, which represents the return value of *heavy_function()*. @@ -90,9 +90,9 @@ result in other parts of your application or display it to the user as needed. Make sure that the `heavy_function()` returns a value. For example: ```python - def heavy_function(...): - ... - return result +def heavy_function(...): + ... + return result ``` When you update the State with the result of *heavy_function()*, you ensure that the user @@ -120,20 +120,24 @@ In this example, the `heavy_function` uses the `invoke_callback` function to sen to the client at different stages of the task. The `user_status` function appends these updates to the `logs` state variable, which is then displayed in the user interface. -1. **heavy_function**: - - It calls `invoke_callback` at different stages to send progress updates to the - `user_status` function. - - After completing the task, it returns the result. +**heavy_function**: + +- It calls `invoke_callback` at different stages to send progress updates to the +`user_status` function. +- After completing the task, it returns the result. + +**user_status**: -2. **user_status**: - - It updates the `logs` state variable with the progress information. +- It updates the `logs` state variable with the progress information. -3. **status_fct**: - - It updates the `result` state variable with the final result of the `heavy_function`. +**status_fct**: -4. **respond**: - - It initiates the long-running task by calling `invoke_long_callback` with the - `heavy_function` and associated status function. +- It updates the `result` state variable with the final result of the `heavy_function`. + +**respond**: + +- It initiates the long-running task by calling `invoke_long_callback` with the +`heavy_function` and associated status function. By using this approach, you can provide real-time updates to the user interface directly from within the `heavy_function`, enhancing the user experience by keeping them informed @@ -146,19 +150,19 @@ Occasionally, it's useful to give regular updates on the progress of a long-runn Taipy's `invoke_long_callback()^` provides a convenient method to accomplish this: ```python linenums="1" - def heavy_function_status(state, status): - if isinstance(status, bool): - if status: - notify(state, "success", "The heavy function has finished!") - else: - notify(state, "error", "The heavy function has failed somehow.") +def heavy_function_status(state, status): + if isinstance(status, bool): + if status: + notify(state, "success", "The heavy function has finished!") else: - notify(state, "info", "The heavy function is still running...") - - def on_action(state): - invoke_long_callback(state, heavy_function, [...heavy_function arguments...], - heavy_function_status, [...heavy_function_status arguments...], - 5000) + notify(state, "error", "The heavy function has failed somehow.") + else: + notify(state, "info", "The heavy function is still running...") + +def on_action(state): + invoke_long_callback(state, heavy_function, [...heavy_function arguments...], + heavy_function_status, [...heavy_function_status arguments...], + 5000) ``` In the code above, in line 13, when you include a *period* parameter, the `heavy_function_status()` @@ -175,9 +179,17 @@ when dealing with hefty operations. ![Approximating Pi](images/approx_pi.png){width=90% : .tp-image } -```python -{% -include-markdown "./src/long_callbacks.py" -comments=false -%} -``` \ No newline at end of file +=== "Python" + ```python + {% + include-markdown "./src/long_callbacks_tgb.py" + comments=false + %} + ``` +=== "Markdown" + ```python + {% + include-markdown "./src/long_callbacks.py" + comments=false + %} + ``` \ No newline at end of file diff --git a/docs/tutorials/articles/long_callbacks/src/long_callbacks.py b/docs/tutorials/articles/long_callbacks/src/long_callbacks.py index f059cb9ea..754d94bee 100644 --- a/docs/tutorials/articles/long_callbacks/src/long_callbacks.py +++ b/docs/tutorials/articles/long_callbacks/src/long_callbacks.py @@ -43,7 +43,7 @@ def heavy_status(state: State, status, pi_list: list): state.status += 1 -def on_action(state: State): +def approximate_pi(state: State): """ When the button is clicked, start the long callback. @@ -54,16 +54,18 @@ def on_action(state: State): state, pi_approx, [int(state.num_iterations)], heavy_status, [], 1000 ) + if __name__ == "__main__": status = 0 num_iterations = 20_000_000 pi_list = [] logs = "Not running" - page = Markdown(""" + page = Markdown( + """ # Approximating **Pi**{: .color-primary} using the Leibniz formula <|{num_iterations}|number|label=Number of iterations|> -<|Approximate Pi|button|on_action=on_action|> +<|Approximate Pi|button|on_action=approximate_pi|> ## Evolution of approximation <|{pi_list}|chart|layout={layout}|>
@@ -71,7 +73,8 @@ def on_action(state: State): ## Logs ### <|{logs}|text|raw|> |> - """) + """ + ) layout = { "xaxis": {"title": "Iteration (Percentage of Total Iterations)"}, diff --git a/docs/tutorials/articles/long_callbacks/src/long_callbacks_tgb.py b/docs/tutorials/articles/long_callbacks/src/long_callbacks_tgb.py new file mode 100644 index 000000000..baa6f3c15 --- /dev/null +++ b/docs/tutorials/articles/long_callbacks/src/long_callbacks_tgb.py @@ -0,0 +1,84 @@ +from taipy.gui import Gui, Markdown, State, invoke_long_callback, notify +import taipy.gui.builder as tgb + + +def pi_approx(num_iterations: int): + """ + Approximate Pi using the Leibniz formula. + + Args: + num_iterations: Number of iterations to compute the approximation. + + Returns: + A list of approximations of Pi, made at each iteration. + """ + k, s = 3.0, 1.0 + pi_list = [] + for i in range(num_iterations): + s = s - ((1 / k) * (-1) ** i) + k += 2 + if (i + 1) % (int(num_iterations / 100) + 1) == 0: + pi_list += [4 * s] + + return pi_list + + +def heavy_status(state: State, status, pi_list: list): + """ + Periodically update the status of the long callback. + + Args: + state: The state of the application. + status: The status of the long callback. + pi_list: The list of approximations of Pi. + """ + state.logs = f"Approximating Pi... ({status}s)" + if isinstance(status, bool): + if status: + state.logs = f"Finished! Approximation: {pi_list[-1]}" + notify(state, "success", "Finished") + state.pi_list = pi_list + else: + notify(state, "error", "An error was raised") + else: + state.status += 1 + + +def approximate_pi(state: State): + """ + When the button is clicked, start the long callback. + + Args: + state: The state of the application. + """ + invoke_long_callback( + state, pi_approx, [int(state.num_iterations)], heavy_status, [], 1000 + ) + + +if __name__ == "__main__": + status = 0 + num_iterations = 20_000_000 + pi_list = [] + logs = "Not running" + + with tgb.Page() as page: + tgb.text("# Approximating **Pi** using the Leibniz formula", mode="md") + tgb.number("{num_iterations}", label="Number of iterations") + tgb.button("Approximate Pi", on_action=approximate_pi) + + tgb.text("## Evolution of approximation", mode="md") + tgb.chart("{pi_list}", layout="{layout}") + + tgb.html("br") + + with tgb.part("card"): + tgb.text("## Logs", mode="md") + tgb.text("### {logs}", mode="md") + + layout = { + "xaxis": {"title": "Iteration (Percentage of Total Iterations)"}, + "yaxis": {"title": "Pi Approximation"}, + } + + Gui(page).run() diff --git a/docs/tutorials/articles/the_data_nodes/index.md b/docs/tutorials/articles/the_data_nodes/index.md index 2e4a1b7d8..ea2ba7b89 100644 --- a/docs/tutorials/articles/the_data_nodes/index.md +++ b/docs/tutorials/articles/the_data_nodes/index.md @@ -33,7 +33,7 @@ Taipy has a set of predefined data nodes ready to be used when configuring your Here’s the list of predefined data nodes: -![data nodes](images/data_notes.png){width=90% : .tp-image } +![data nodes](images/data_notes.png){width=80% : .tp-image } ## Pickle Data Node diff --git a/docs/tutorials/articles/using_tables/index.md b/docs/tutorials/articles/using_tables/index.md index b478269be..049d07eac 100644 --- a/docs/tutorials/articles/using_tables/index.md +++ b/docs/tutorials/articles/using_tables/index.md @@ -22,22 +22,42 @@ You can see all the code with the table features we talked about at the end of t First, let's see how you make tables in Taipy: -```python title="main.py" -from taipy.gui import Gui, Markdown -import pandas as pd - -if __name__ == "__main__": - food_df = pd.DataFrame({ - "Meal": ["Lunch", "Dinner", "Lunch", "Lunch", "Breakfast", "Breakfast", "Lunch", "Dinner"], - "Category": ["Food", "Food", "Drink", "Food", "Food", "Drink", "Dessert", "Dessert"], - "Name": ["Burger", "Pizza", "Soda", "Salad", "Pasta", "Water", "Ice Cream", "Cake"], - "Calories": [300, 400, 150, 200, 500, 0, 400, 500], - }) - - main_md = Markdown("<|{food_df}|table|>") - - Gui(page=main_md).run() -``` +=== "Python" + ```python title="main.py" + from taipy.gui import Gui, Markdown + import pandas as pd + import taipy.gui.builder as tgb + + if __name__ == "__main__": + food_df = pd.DataFrame({ + "Meal": ["Lunch", "Dinner", "Lunch", "Lunch", "Breakfast", "Breakfast", "Lunch", "Dinner"], + "Category": ["Food", "Food", "Drink", "Food", "Food", "Drink", "Dessert", "Dessert"], + "Name": ["Burger", "Pizza", "Soda", "Salad", "Pasta", "Water", "Ice Cream", "Cake"], + "Calories": [300, 400, 150, 200, 500, 0, 400, 500], + }) + + with tgb.Page() as page: + tgb.table("{food_df}") + + Gui(page=page).run() + ``` +=== "Markdown" + ```python title="main.py" + from taipy.gui import Gui, Markdown + import pandas as pd + + if __name__ == "__main__": + food_df = pd.DataFrame({ + "Meal": ["Lunch", "Dinner", "Lunch", "Lunch", "Breakfast", "Breakfast", "Lunch", "Dinner"], + "Category": ["Food", "Food", "Drink", "Food", "Food", "Drink", "Dessert", "Dessert"], + "Name": ["Burger", "Pizza", "Soda", "Salad", "Pasta", "Water", "Ice Cream", "Cake"], + "Calories": [300, 400, 150, 200, 500, 0, 400, 500], + }) + + main_md = Markdown("<|{food_df}|table|>") + + Gui(page=main_md).run() + ``` The table definition `<|{food_df}|table|>` (a syntax often used in Taipy) has these parts: @@ -57,9 +77,15 @@ function to be performed. In our food tracker example, an application could be t 1. Group by *Category*; and 2. Sum the *Calories*. -```python -main_md = Markdown("<|{food_df}|table|group_by[Category]=True|apply[Calories]=sum|>") -``` +=== "Python" + ```python + tgb.table("{food_df}", group_by__Category=True, apply__Calories="sum") + ``` +=== "Markdown" + ```python + main_md = Markdown("<|{food_df}|table|group_by[Category]=True|apply[Calories]=sum|>") + ``` + To configure table aggregation, you add two properties to the table: 1. `group_by[Category]=True`: This tells the table to group data by the **Category** column. @@ -90,12 +116,18 @@ column. To add filters to our table, it's easy: we set the `filter` property to True, like this: -```python -main_md = Markdown("<|{food_df}|table|filter=True|>") -``` -As with all control Boolean properties, we can remove the '=True' part, making it: -`<|{food_df}|table|filter|>`. +=== "Python" + ```python + tgb.table("{food_df}", filter=True) + ``` +=== "Markdown" + ```python + main_md = Markdown("<|{food_df}|table|filter=True|>") + ``` + + As with all control Boolean properties, we can remove the '=True' part, making it: + `<|{food_df}|table|filter|>`. ## Styling (Stylekit) @@ -115,9 +147,14 @@ those who have no knowledge of CSS. We achieved this by just putting the **rows-bordered** Stylekit CSS class into the `class_name` property of the table control: -```python -main_md = Markdown("<|{food_df}|table|class_name=rows-bordered|>") -``` +=== "Python" + ```python + tgb.table("{food_df}", class_name="rows-bordered") + ``` +=== "Markdown" + ```python + main_md = Markdown("<|{food_df}|table|class_name=rows-bordered|>") + ``` To learn more about how Stylekit supports Taipy tables, you can check the documentation [here](../../../refmans/gui/viselements/generic/table.md#styling). If you want to explore the @@ -147,18 +184,33 @@ The *row_class_name* property accepts a function. This function is applied to ea and returns a string specifying the CSS class to be used for that particular row. To create the table mentioned above, you can use the following code: -```python title="main.py" -def table_style(state, index, row): - return "highlight-row" if row.Category == "Dessert" else "" +=== "Python" + ```python title="main.py" + def table_style(state, index, row): + return "highlight-row" if row.Category == "Dessert" else "" -table_properties = { - "class_name": "rows-bordered rows-similar", # optional - "row_class_name": table_style, -} + table_properties = { + "class_name": "rows-bordered rows-similar", # optional + "row_class_name": table_style, + } -main_md = Markdown("<|{food_df}|table|properties=table_properties|>") -# or Markdown("<|{food_df}|table|class_name=rows-bordered rows-similar|row_class_name=table_style|>") -``` + with tgb.Page() as page: + tgb.table("{food_df}", properties=table_properties) + # or tgb.table("{food_df}", class_name="rows-bordered rows-similar", row_class_name=table_style) + ``` +=== "Markdown" + ```python title="main.py" + def table_style(state, index, row): + return "highlight-row" if row.Category == "Dessert" else "" + + table_properties = { + "class_name": "rows-bordered rows-similar", # optional + "row_class_name": table_style, + } + + main_md = Markdown("<|{food_df}|table|properties=table_properties|>") + # or Markdown("<|{food_df}|table|class_name=rows-bordered rows-similar|row_class_name=table_style|>") + ``` ```css /* main.css */ @@ -194,22 +246,41 @@ function, then clicking the tick triggers the callback function: The following code can be used to implement basic editing functionality: -```python -def food_df_on_edit(state, var_name, payload): - index = payload["index"] # row index - col = payload["col"] # column name - value = payload["value"] # new value cast to the column type - user_value = payload["user_value"] # new value as entered by the user - - # state.food_df.loc[index, col] = value # Don't do this! - old_value = state.food_df.loc[index, col] - new_food_df = state.food_df.copy() - new_food_df.loc[index, col] = value - state.food_df = new_food_df - notify(state, "I", f"Edited value from '{old_value}' to '{value}'. (index '{index}', column '{col}')") - -main_md = Markdown("<|{food_df}|table|editable|on_edit=food_df_on_edit|>") -``` +=== "Python" + ```python title="main.py" + def food_df_on_edit(state, var_name, payload): + index = payload["index"] # row index + col = payload["col"] # column name + value = payload["value"] # new value cast to the column type + user_value = payload["user_value"] # new value as entered by the user + + # state.food_df.loc[index, col] = value # Don't do this! + old_value = state.food_df.loc[index, col] + new_food_df = state.food_df.copy() + new_food_df.loc[index, col] = value + state.food_df = new_food_df + notify(state, "I", f"Edited value from '{old_value}' to '{value}'. (index '{index}', column '{col}')") + + with tgb.Page() as page: + tgb.table("{food_df}", editable=True, on_edit=food_df_on_edit) + ``` +=== "Markdown" + ```python + def food_df_on_edit(state, var_name, payload): + index = payload["index"] # row index + col = payload["col"] # column name + value = payload["value"] # new value cast to the column type + user_value = payload["user_value"] # new value as entered by the user + + # state.food_df.loc[index, col] = value # Don't do this! + old_value = state.food_df.loc[index, col] + new_food_df = state.food_df.copy() + new_food_df.loc[index, col] = value + state.food_df = new_food_df + notify(state, "I", f"Edited value from '{old_value}' to '{value}'. (index '{index}', column '{col}')") + + main_md = Markdown("<|{food_df}|table|editable|on_edit=food_df_on_edit|>") + ``` The table documentation provides more information on the function signature which is slightly different for each data modification property. The code example above is self-explanatory though. @@ -229,15 +300,27 @@ speficied in the *on_add* property. We can implement the functionality above as follows: -```python -def food_df_on_add(state, var_name, payload): - empty_row = pd.DataFrame([[None for _ in state.food_df.columns]], columns=state.food_df.columns) - state.food_df = pd.concat([empty_row, state.food_df], axis=0, ignore_index=True) +=== "Python" + ```python + def food_df_on_add(state, var_name, payload): + empty_row = pd.DataFrame([[None for _ in state.food_df.columns]], columns=state.food_df.columns) + state.food_df = pd.concat([empty_row, state.food_df], axis=0, ignore_index=True) - notify(state, "S", f"Added a new row.") + notify(state, "S", f"Added a new row.") -main_md = Markdown("<|{food_df}|table|editable|on_add=food_df_on_add|>") -``` + with tgb.Page() as page: + tgb.table("{food_df}", editable=True, on_add=food_df_on_add) + ``` +=== "Markdown" + ```python + def food_df_on_add(state, var_name, payload): + empty_row = pd.DataFrame([[None for _ in state.food_df.columns]], columns=state.food_df.columns) + state.food_df = pd.concat([empty_row, state.food_df], axis=0, ignore_index=True) + + notify(state, "S", f"Added a new row.") + + main_md = Markdown("<|{food_df}|table|editable|on_add=food_df_on_add|>") + ``` This code simply adds a new empty row to the top of the table (DataFrame). You can customize the callback function accordingly if your use case requires @@ -251,15 +334,27 @@ Finally, the deletion process works as follows: We can implement basic functionality with the following code: -```python -def food_df_on_delete(state, var_name, payload): - index = payload["index"] # row index +=== "Python" + ```python + def food_df_on_delete(state, var_name, payload): + index = payload["index"] # row index - state.food_df = state.food_df.drop(index=index) - notify(state, "E", f"Deleted row at index '{index}'") + state.food_df = state.food_df.drop(index=index) + notify(state, "E", f"Deleted row at index '{index}'") -main_md = Markdown("<|{food_df}|table|editable|on_delete=food_df_on_delete|>") -``` + with tgb.Page() as page: + tgb.table("{food_df}", editable=True, on_delete=food_df_on_delete) + ``` +=== "Markdown" + ```python + def food_df_on_delete(state, var_name, payload): + index = payload["index"] # row index + + state.food_df = state.food_df.drop(index=index) + notify(state, "E", f"Deleted row at index '{index}'") + + main_md = Markdown("<|{food_df}|table|editable|on_delete=food_df_on_delete|>") + ``` ## Complete Code @@ -270,61 +365,119 @@ the [documentation](../../../refmans/gui/viselements/generic/table.md) for more Lastly, here's the code that combines all the features we discussed in this article, used to create the application shown at the beginning of the article: -```python -from taipy.gui import Gui, Markdown, notify -import pandas as pd - - -def food_df_on_edit(state, var_name, payload): - index = payload["index"] # row index - col = payload["col"] # column name - value = payload["value"] # new value cast to the column type - user_value = payload["user_value"] # new value as entered by the user - - old_value = state.food_df.loc[index, col] - new_food_df = state.food_df.copy() - new_food_df.loc[index, col] = value - state.food_df = new_food_df - notify(state, "I", f"Edited value from '{old_value}' to '{value}'. (index '{index}', column '{col}')") - - -def food_df_on_delete(state, var_name, payload): - index = payload["index"] # row index - - state.food_df = state.food_df.drop(index=index) - notify(state, "E", f"Deleted row at index '{index}'") - - -def food_df_on_add(state, var_name, payload): - empty_row = pd.DataFrame([[None for _ in state.food_df.columns]], columns=state.food_df.columns) - state.food_df = pd.concat([empty_row, state.food_df], axis=0, ignore_index=True) - - notify(state, "S", f"Added a new row.") - -if __name__ == "__main__": - food_df = pd.DataFrame({ - "Meal": ["Lunch", "Dinner", "Lunch", "Lunch", "Breakfast", "Breakfast", "Lunch", "Dinner"], - "Category": ["Food", "Food", "Drink", "Food", "Food", "Drink", "Dessert", "Dessert"], - "Name": ["Burger", "Pizza", "Soda", "Salad", "Pasta", "Water", "Ice Cream", "Cake"], - "Calories": [300, 400, 150, 200, 500, 0, 400, 500], - }) - - table_properties = { - "class_name": "rows-bordered", - "editable": True, - "filter": True, - "on_edit": food_df_on_edit, - "on_delete": food_df_on_delete, - "on_add": food_df_on_add, - "group_by[Category]": True, - "apply[Calories]": "sum", - } - - main_md = Markdown(""" -# Daily Calorie Tracker - -<|{food_df}|table|properties=table_properties|> - """) - - Gui(page=main_md).run() -``` +=== "Python" + ```python + from taipy.gui import Gui, notify + import pandas as pd + import taipy.gui.builder as tgb + + + def food_df_on_edit(state, var_name, payload): + index = payload["index"] # row index + col = payload["col"] # column name + value = payload["value"] # new value cast to the column type + user_value = payload["user_value"] # new value as entered by the user + + old_value = state.food_df.loc[index, col] + new_food_df = state.food_df.copy() + new_food_df.loc[index, col] = value + state.food_df = new_food_df + notify(state, "I", f"Edited value from '{old_value}' to '{value}'. (index '{index}', column '{col}')") + + + def food_df_on_delete(state, var_name, payload): + index = payload["index"] # row index + + state.food_df = state.food_df.drop(index=index) + notify(state, "E", f"Deleted row at index '{index}'") + + + def food_df_on_add(state, var_name, payload): + empty_row = pd.DataFrame([[None for _ in state.food_df.columns]], columns=state.food_df.columns) + state.food_df = pd.concat([empty_row, state.food_df], axis=0, ignore_index=True) + + notify(state, "S", f"Added a new row.") + + if __name__ == "__main__": + food_df = pd.DataFrame({ + "Meal": ["Lunch", "Dinner", "Lunch", "Lunch", "Breakfast", "Breakfast", "Lunch", "Dinner"], + "Category": ["Food", "Food", "Drink", "Food", "Food", "Drink", "Dessert", "Dessert"], + "Name": ["Burger", "Pizza", "Soda", "Salad", "Pasta", "Water", "Ice Cream", "Cake"], + "Calories": [300, 400, 150, 200, 500, 0, 400, 500], + }) + + table_properties = { + "class_name": "rows-bordered", + "editable": True, + "filter": True, + "on_edit": food_df_on_edit, + "on_delete": food_df_on_delete, + "on_add": food_df_on_add, + "group_by[Category]": True, + "apply[Calories]": "sum", + } + + with tgb.Page() as page: + tgb.table("{food_df}", properties=table_properties) + + Gui(page=page).run() + ``` +=== "Markdown" + ```python + from taipy.gui import Gui, Markdown, notify + import pandas as pd + + + def food_df_on_edit(state, var_name, payload): + index = payload["index"] # row index + col = payload["col"] # column name + value = payload["value"] # new value cast to the column type + user_value = payload["user_value"] # new value as entered by the user + + old_value = state.food_df.loc[index, col] + new_food_df = state.food_df.copy() + new_food_df.loc[index, col] = value + state.food_df = new_food_df + notify(state, "I", f"Edited value from '{old_value}' to '{value}'. (index '{index}', column '{col}')") + + + def food_df_on_delete(state, var_name, payload): + index = payload["index"] # row index + + state.food_df = state.food_df.drop(index=index) + notify(state, "E", f"Deleted row at index '{index}'") + + + def food_df_on_add(state, var_name, payload): + empty_row = pd.DataFrame([[None for _ in state.food_df.columns]], columns=state.food_df.columns) + state.food_df = pd.concat([empty_row, state.food_df], axis=0, ignore_index=True) + + notify(state, "S", f"Added a new row.") + + if __name__ == "__main__": + food_df = pd.DataFrame({ + "Meal": ["Lunch", "Dinner", "Lunch", "Lunch", "Breakfast", "Breakfast", "Lunch", "Dinner"], + "Category": ["Food", "Food", "Drink", "Food", "Food", "Drink", "Dessert", "Dessert"], + "Name": ["Burger", "Pizza", "Soda", "Salad", "Pasta", "Water", "Ice Cream", "Cake"], + "Calories": [300, 400, 150, 200, 500, 0, 400, 500], + }) + + table_properties = { + "class_name": "rows-bordered", + "editable": True, + "filter": True, + "on_edit": food_df_on_edit, + "on_delete": food_df_on_delete, + "on_add": food_df_on_add, + "group_by[Category]": True, + "apply[Calories]": "sum", + } + + main_md = Markdown(""" + # Daily Calorie Tracker + + <|{food_df}|table|properties=table_properties|> + """) + + Gui(page=main_md).run() + ```