Skip to content

Commit

Permalink
[Bug/Docs] improve docs and fix bug on custom ag_grid (#357)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
maxschulz-COL and pre-commit-ci[bot] authored Mar 11, 2024
1 parent 10f2060 commit 3fbbb83
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!--
A new scriv changelog fragment.
Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Highlights ✨
- A bullet item for the Highlights ✨ category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Removed
- A bullet item for the Removed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Added
- A bullet item for the Added category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Changed
- A bullet item for the Changed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Deprecated
- A bullet item for the Deprecated category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Fixed
- A bullet item for the Fixed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Security
- A bullet item for the Security category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions vizro-core/docs/pages/API-reference/captured-callables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Table functions

API reference for all pre-defined [`CapturedCallable`][vizro.models.types.CapturedCallable] table functions to be used in the
[`AgGrid`][vizro.models.AgGrid] and [`Table`][vizro.models.Table] models. Visit the How-to guide on [tables](../user-guides/table.md)
for more information.

::: vizro.tables
options:
show_source: true
74 changes: 71 additions & 3 deletions vizro-core/docs/pages/user-guides/custom-tables.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# How to create custom Dash AG Grids and Dash DataTables

In cases where the available arguments for the [`AgGrid`][vizro.models.AgGrid] or [`Table`][vizro.models.Table] models are not sufficient,
In cases where the available arguments for the [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] models are not sufficient,
you can create a custom Dash AG Grid or Dash DataTable.

One reason could be that you want to create a table/grid that requires computations that can be controlled by parameters (see the example below).
Expand All @@ -12,7 +12,7 @@ For this, similar to how one would create a [custom chart](../user-guides/custom
- The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
- The table should be derived from and require only one `pandas.DataFrame` (e.g. any further dataframes added through other arguments will not react to dashboard components such as `Filter`).

The following example shows a possible version of a custom table. In this case the argument `chosen_columns` was added, which you can control with a parameter:
The following examples show a possible version of a custom table. In this case the argument `chosen_columns` was added, which you can control with a parameter:

??? example "Custom Dash DataTable"
=== "app.py"
Expand All @@ -30,7 +30,7 @@ The following example shows a possible version of a custom table. In this case t


@capture("table")
def my_custom_table(data_frame=None, chosen_columns: List[str] = None):
def my_custom_table(chosen_columns: List[str], data_frame=None):
"""Custom table."""
columns = [{"name": i, "id": i} for i in chosen_columns]
defaults = {
Expand Down Expand Up @@ -75,3 +75,71 @@ The following example shows a possible version of a custom table. In this case t
[![Table3]][Table3]

[Table3]: ../../assets/user_guides/table/custom_table.png

??? example "Custom Dash AgGrid"
=== "app.py"
```py
from typing import List

import vizro.models as vm
import vizro.plotly.express as px
from dash_ag_grid import AgGrid
from vizro import Vizro
from vizro.models.types import capture

df = px.data.gapminder().query("year == 2007")


@capture("ag_grid")
def my_custom_aggrid(chosen_columns: List[str], data_frame=None):
"""Custom ag_grid."""
defaults = {
"className": "ag-theme-quartz-dark ag-theme-vizro",
"defaultColDef": {
"resizable": True,
"sortable": True,
"filter": True,
"filterParams": {
"buttons": ["apply", "reset"],
"closeOnApply": True,
},
"flex": 1,
"minWidth": 70,
},
"style": {"height": "100%"},
}
return AgGrid(
columnDefs=[{"field": col} for col in chosen_columns], rowData=data_frame.to_dict("records"), **defaults
)


page = vm.Page(
title="Example of a custom Dash AgGrid",
components=[
vm.AgGrid(
id="custom_ag_grid",
title="Custom Dash AgGrid",
figure=my_custom_aggrid(
data_frame=df, chosen_columns=["country", "continent", "lifeExp", "pop", "gdpPercap"]
),
),
],
controls=[
vm.Parameter(
targets=["custom_ag_grid.chosen_columns"],
selector=vm.Dropdown(title="Choose columns", options=df.columns.to_list(), multi=True),
)
],
)
dashboard = vm.Dashboard(pages=[page])

Vizro().build(dashboard).run()
```
=== "app.yaml"
```yaml
# Custom Ag Grids are currently only possible via python configuration
```
=== "Result"
[![GridCustom]][GridCustom]

[GridCustom]: ../../assets/user_guides/table/custom_grid.png
4 changes: 3 additions & 1 deletion vizro-core/docs/pages/user-guides/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ To add a [`AgGrid`][vizro.models.AgGrid] to your page, do the following:
- Enter the `dash_ag_grid` function under the `figure` argument (imported via `from vizro.tables import dash_ag_grid`).

The Vizro version of this AG Grid differs in one way from the original Dash AG Grid: it requires the user to provide a pandas dataframe as source of data.
This must be entered under the argument `data_frame`. All other [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments.
This must be entered under the argument `data_frame`. Most other [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments.
Note that some defaults are set for some of the arguments (e.g. for `columnDefs`) to help with styling and usability.
In some cases a parameter may not work because it e.g. requires an additional callback to function. In that case you can try
creating a [custom AG Grid callable](custom-tables.md) or reach out to the Vizro team for help.


!!! example "Basic Dash AG Grid"
Expand Down
3 changes: 0 additions & 3 deletions vizro-core/examples/_dev/assets/images/logo.svg

This file was deleted.

1 change: 1 addition & 0 deletions vizro-core/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ nav:
- Models: pages/API-reference/models.md
- Data manager: pages/API-reference/manager.md
- Actions: pages/API-reference/actions.md
- Table functions: pages/API-reference/captured-callables.md
- Explanation:
- Why Vizro?: pages/explanation/why-vizro.md
- Compatibility: pages/explanation/compatibility.md
Expand Down
5 changes: 3 additions & 2 deletions vizro-core/src/vizro/models/_components/ag_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ def build(self):
# setting as the object that is built on-page-load and rendered finally.
dash_ag_grid_conf = self.figure._arguments.copy()
dash_ag_grid_conf["data_frame"] = pd.DataFrame()
dash_ag_grid_conf["id"] = self._input_component_id
grid = self.figure._function(**dash_ag_grid_conf)
grid.id = self._input_component_id

clientside_callback(
ClientsideFunction(namespace="clientside", function_name="update_ag_grid_theme"),
Expand All @@ -113,7 +114,7 @@ def build(self):
return dcc.Loading(
[
html.H3(self.title, className="table-title") if self.title else None,
html.Div(self.figure._function(**dash_ag_grid_conf), id=self.id, className="table-container"),
html.Div(grid, id=self.id, className="table-container"),
],
id=f"{self.id}_outer",
color="grey",
Expand Down
4 changes: 2 additions & 2 deletions vizro-core/src/vizro/tables/_dash_ag_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@


@capture("ag_grid")
def dash_ag_grid(data_frame, **kwargs):
"""Implementation of `dash_ag_grid.AgGrid` with sensible defaults."""
def dash_ag_grid(data_frame: pd.DataFrame, **kwargs) -> dag.AgGrid:
"""Implementation of `dash_ag_grid.AgGrid` with sensible defaults to be used in [`AgGrid`][vizro.models.AgGrid]."""
defaults = {
"className": "ag-theme-quartz-dark ag-theme-vizro",
"columnDefs": [{"field": col} for col in data_frame.columns],
Expand Down
4 changes: 2 additions & 2 deletions vizro-core/src/vizro/tables/_dash_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@


@capture("table")
def dash_data_table(data_frame: pd.DataFrame, **kwargs):
"""Standard `dash_table.DataTable`."""
def dash_data_table(data_frame: pd.DataFrame, **kwargs) -> dash_table.DataTable:
"""Standard `dash_table.DataTable` with sensible defaults to be used in [`Table`][vizro.models.Table]."""
defaults = {
"columns": [{"name": col, "id": col} for col in data_frame.columns],
"style_as_list_view": True,
Expand Down
39 changes: 39 additions & 0 deletions vizro-core/tests/unit/vizro/tables/test_dash_ag_grid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import dash_ag_grid as dag
import pandas as pd
import vizro.models as vm
from asserts import assert_component_equal
from dash import dcc, html
from vizro.models.types import capture
from vizro.tables import dash_ag_grid

data = pd.DataFrame(
Expand Down Expand Up @@ -30,3 +33,39 @@ def test_dash_ag_grid(self):
)
# we could test other properties such as defaultColDef,
# but this would just test our chosen defaults, and no functionality really


class TestCustomDashAgGrid:
def test_custom_dash_ag_grid(self):
"""Tests whether a custom created grid callable can be correctly be built in vm.AgGrid."""
id = "custom_ag_grid"

@capture("ag_grid")
def custom_ag_grid(data_frame):
return dag.AgGrid(
columnDefs=[{"field": col} for col in data_frame.columns],
rowData=data_frame.to_dict("records"),
)

grid_model = vm.AgGrid(
id=id,
figure=custom_ag_grid(data_frame=data),
)
grid_model.pre_build()
custom_grid = grid_model.build()

expected_grid = dcc.Loading(
[
None,
html.Div(
dag.AgGrid(id="__input_custom_ag_grid", columnDefs=[], rowData=[]),
id=id,
className="table-container",
),
],
id=f"{id}_outer",
color="grey",
parent_className="loading-container",
)

assert_component_equal(custom_grid, expected_grid)
40 changes: 39 additions & 1 deletion vizro-core/tests/unit/vizro/tables/test_dash_table.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pandas as pd
import vizro.models as vm
from asserts import assert_component_equal
from dash import dash_table
from dash import dash_table, dcc, html
from vizro.models.types import capture
from vizro.tables import dash_data_table

data = pd.DataFrame(
Expand Down Expand Up @@ -46,3 +48,39 @@ def test_dash_data_table(self):
],
),
)


class TestCustomDashDataTable:
def test_custom_dash_data_table(self):
"""Tests whether a custom created table callable can be correctly be built in vm.Table."""
id = "custom_dash_data_table"

@capture("table")
def custom_dash_data_table(data_frame):
return dash_table.DataTable(
columns=[{"name": col, "id": col} for col in data_frame.columns],
data=data_frame.to_dict("records"),
)

table = vm.Table(
id=id,
figure=custom_dash_data_table(data_frame=data),
)
table.pre_build()

custom_table = table.build()

expected_table = dcc.Loading(
html.Div(
[
None,
html.Div(dash_table.DataTable(id="__input_custom_dash_data_table"), id=id),
],
className="table-container",
id=f"{id}_outer",
),
color="grey",
parent_className="loading-container",
)

assert_component_equal(custom_table, expected_table)

0 comments on commit 3fbbb83

Please sign in to comment.