diff --git a/CODEOWNERS b/CODEOWNERS index a8f6300ee..83a984cd3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,3 @@ * @Joseph-Perkins @antonymilne @huong-li-nguyen @maxschulz-COL @Anna-Xiong +vizro-ai/docs/ @stichbury +vizro-core/docs/ @stichbury diff --git a/vizro-core/changelog.d/20240301_124716_maximilian_schulz_aggrid_docs_2.md b/vizro-core/changelog.d/20240301_124716_maximilian_schulz_aggrid_docs_2.md new file mode 100644 index 000000000..6f680acca --- /dev/null +++ b/vizro-core/changelog.d/20240301_124716_maximilian_schulz_aggrid_docs_2.md @@ -0,0 +1,49 @@ + + +### Highlights ✨ + +- Introduce `AgGrid` as a new `Page` component, allowing the usage of + [AG Grid](https://www.ag-grid.com/javascript-data-grid/scrolling-scenarios/) in + `Vizro`. See the [user guide on tables](https://vizro.readthedocs.io/en/stable/pages/user_guides/table/) + for more information. ([#289](https://github.com/mckinsey/vizro/pull/289),[#268](https://github.com/mckinsey/vizro/pull/268),[#324](https://github.com/mckinsey/vizro/pull/324)) + + + + + + + diff --git a/vizro-core/docs/assets/user_guides/table/aggrid.png b/vizro-core/docs/assets/user_guides/table/aggrid.png new file mode 100644 index 000000000..517812f30 Binary files /dev/null and b/vizro-core/docs/assets/user_guides/table/aggrid.png differ diff --git a/vizro-core/docs/assets/user_guides/table/formatted_aggrid.png b/vizro-core/docs/assets/user_guides/table/formatted_aggrid.png new file mode 100644 index 000000000..eecc9c2f9 Binary files /dev/null and b/vizro-core/docs/assets/user_guides/table/formatted_aggrid.png differ diff --git a/vizro-core/docs/assets/user_guides/table/styled_aggrid.png b/vizro-core/docs/assets/user_guides/table/styled_aggrid.png new file mode 100644 index 000000000..d371b160a Binary files /dev/null and b/vizro-core/docs/assets/user_guides/table/styled_aggrid.png differ diff --git a/vizro-core/docs/pages/user-guides/custom-tables.md b/vizro-core/docs/pages/user-guides/custom-tables.md index 0870e2b4b..c409c7c43 100644 --- a/vizro-core/docs/pages/user-guides/custom-tables.md +++ b/vizro-core/docs/pages/user-guides/custom-tables.md @@ -1,14 +1,16 @@ -# How to create custom tables +# How to create custom Dash AG Grids and Dash DataTables -If you want to use the [`Table`][vizro.models.Table] model to and to create a custom [table](table.md) you can create your own custom table, e.g. when requiring computations that can be controlled by parameters. +In cases where the available arguments for the [`AgGrid`][vizro.models.AgGrid] or [`Table`][vizro.models.Table] models are not sufficient, +you can create a custom Dash AG Grid or Dash DataTable. -For this, similar to how one would create a [custom chart](../user-guides/custom-charts.md), simply do the following: +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). -- define a function that returns a `dash_table.DataTable` object -- decorate it with the `@capture("table")` decorator -- 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`) +For this, similar to how one would create a [custom chart](../user-guides/custom-charts.md), simply do the following: +- Define a function that returns a `dash_ag_grid.AgGrid` or `dash_table.DataTable` object. +- Decorate it with the `@capture("ag_grid")` or `@capture("table")` decorator respectively. +- 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: diff --git a/vizro-core/docs/pages/user-guides/table.md b/vizro-core/docs/pages/user-guides/table.md index f7a3525b2..c7a3fad5c 100755 --- a/vizro-core/docs/pages/user-guides/table.md +++ b/vizro-core/docs/pages/user-guides/table.md @@ -1,25 +1,316 @@ # How to use tables -This guide shows you how to use tables to visualize your data in the dashboard. +This guide shows you how to visualize tables in Vizro. -The [`Table`][vizro.models.Table] model allows you to visualize data in a tabular format. +There are two ways to visualize tables in Vizro, using either [AG Grid](#ag-grid) or [Dash DataTable](#dash-datatable). +In general, [AG Grid](#ag-grid) is Vizro's recommended table implementation, but in some cases it may make sense to use the [Dash DataTable](#dash-datatable) instead. -To add a [`Table`][vizro.models.Table] to your page, do the following: +## How to choose between AG Grid and Dash DataTable + +Vizro offers two models - the [`AgGrid`][vizro.models.AgGrid] model and the [`Table`][vizro.models.Table] model - for the above two approaches respectively. +They both visualize tabular data in similar ways. + +The main difference between the two is that the [`AgGrid`][vizro.models.AgGrid] model is based on Plotly's [Dash AG Grid](https://dash.plotly.com/dash-ag-grid) component, +while the [`Table`][vizro.models.Table] model is based on the [Dash DataTable](https://dash.plotly.com/datatable) component. + +Both approaches have similar base features, and are configurable in similar ways. However, the AG Grid offers more advanced features out-of-the-box, is more customizable +and also ships a powerful enterprise version. This is why it is Vizro's recommended table implementation. At the same time, the Dash DataTable can be used if developers are +already familiar with it, or if some custom functionality is easier to implement using the Dash DataTable. + + +## AG Grid + +[AG Grid](https://www.ag-grid.com/) is an interactive table/grid component designed for viewing, editing, and exploring large datasets. It +is Vizro's recommended table implementation. + +The Vizro [`AgGrid`][vizro.models.AgGrid] model is based on the [Dash AG Grid](https://dash.plotly.com/dash-ag-grid), which is in turn based the +original [Javascript implementation](https://www.ag-grid.com/). + +### Basic usage + +To add a [`AgGrid`][vizro.models.AgGrid] to your page, do the following: + +- Insert the [`AgGrid`][vizro.models.AgGrid] model into the `components` argument of the +[`Page`][vizro.models.Page] model. +- 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. +Note that some defaults are set for some of the arguments (e.g. for `columnDefs`) to help with styling and usability. + + +!!! example "Basic Dash AG Grid" + === "app.py" + ```py + import vizro.models as vm + import vizro.plotly.express as px + from vizro import Vizro + from vizro.tables import dash_ag_grid + + df = px.data.gapminder() + + page = vm.Page( + title="Example of a Dash AG Grid", + components=[ + vm.AgGrid(title="Dash AG Grid", figure=dash_ag_grid(data_frame=df)), + ], + controls=[vm.Filter(column="continent")], + ) + dashboard = vm.Dashboard(pages=[page]) + + Vizro().build(dashboard).run() + ``` + === "app.yaml" + ```yaml + # Still requires a .py to register data connector in Data Manager and parse yaml configuration + # See from_yaml example + pages: + - components: + - figure: + _target_: dash_ag_grid + data_frame: gapminder + title: Dash AG Grid + type: ag_grid + controls: + - column: continent + type: filter + title: Example of a Dash AG Grid + ``` + === "Result" + [![AGGrid]][AGGrid] + + [AGGrid]: ../../assets/user_guides/table/aggrid.png -- insert the [`Table`][vizro.models.Table] model into the `components` argument of the -[`Page`][vizro.models.Page] model -- enter any of the currently available table functions +### Formatting columns -See below for an overview of currently supported table functions. +#### Numbers -### Dash DataTable +One of the most common tasks when working with tables is to format the columns so that displayed numbers are more readable. +In order to do this, you can use the native functionality of [Value Formatters](https://dash.plotly.com/dash-ag-grid/value-formatters) +or the Vizro pre-defined [Custom Cell Data Types](https://dash.plotly.com/dash-ag-grid/cell-data-types#providing-custom-cell-data-types) as shown below. -The [Dash DataTable](https://dash.plotly.com/datatable) is an interactive table component designed for viewing, editing, and exploring large datasets. +The available custom cell types for Vizro are `dollar`, `euro`, `percentage` and `numeric`. + +In order to use these, define your desired `` alongside the chosen `cellDataType` in +the `columnDefs` argument of your `dash_ag_grid` function: -You can use the [Dash DataTable](https://dash.plotly.com/datatable) in Vizro by importing ```py -from vizro.tables import dash_data_table +columnDefs = [{"field": "", "cellDataType": "euro"}] ``` + +In the example below we select and format some columns of the gapminder dataset. + +??? example "AG Grid with formatted columns" + === "app.py" + ```py + import vizro.models as vm + import vizro.plotly.express as px + from vizro import Vizro + from vizro.tables import dash_ag_grid + + df = px.data.gapminder() + + columnDefs = [{"field": "country"}, {"field": "year"}, {"field": "lifeExp", "cellDataType": "numeric"}, + {"field": "gdpPercap", "cellDataType": "dollar"}, {"field": "pop", "cellDataType": "numeric"}] + + page = vm.Page( + title="Example of AG Grid with formatted columns", + components=[ + vm.AgGrid( + title="AG Grid with formatted columns", + figure=dash_ag_grid( + data_frame=df, + columnDefs=columnDefs, + ), + ) + ], + ) + + dashboard = vm.Dashboard(pages=[page]) + + Vizro().build(dashboard).run() + ``` + === "app.yaml" + ```yaml + # Still requires a .py to register data connector in Data Manager and parse yaml configuration + # See from_yaml example + pages: + - components: + - figure: + _target_: dash_ag_grid + data_frame: gapminder + columnDefs: + - field: country + - field: year + - field: lifeExp + cellDataType: numeric + - field: gdpPercap + cellDataType: dollar + - field: pop + cellDataType: numeric + title: AG Grid with formatted columns + type: ag_grid + title: Example of AG Grid with formatted columns + ``` + === "Result" + [![AGGrid2]][AGGrid2] + + [AGGrid2]: ../../assets/user_guides/table/formatted_aggrid.png + +#### Dates + +For the [`AgGrid`][vizro.models.AgGrid] model to sort and filter dates correctly, the date must either be of +string format `yyyy-mm-dd` (see [Dash AG Grid docs](https://dash.plotly.com/dash-ag-grid/date-filters#example:-date-filter)) +or a pandas datetime object. Any pandas datetime column will be transformed into the `yyyy-mm-dd` format automatically. + +#### Objects/Strings + +No specific formatting is available for custom objects and strings, however you can make use of [Value Formatters](https://dash.plotly.com/dash-ag-grid/value-formatters) +to format e.g. displayed strings automatically. + + +### Styling and modifying the AG Grid + +As mentioned above, all [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments. Below you can find +an example of a styled AG Grid where some conditional formatting is applied, and where the columns are editable, but not filterable or resizable. +There are many more ways to alter the grid beyond this showcase. + +??? example "Styled and modified Dash AG Grid" + === "app.py" + ```py + import vizro.models as vm + import vizro.plotly.express as px + from vizro import Vizro + from vizro.tables import dash_ag_grid + + df = px.data.gapminder() + + cellStyle = { + "styleConditions": [ + { + "condition": "params.value < 1045", + "style": {"backgroundColor": "#ff9222"}, + }, + { + "condition": "params.value >= 1045 && params.value <= 4095", + "style": {"backgroundColor": "#de9e75"}, + }, + { + "condition": "params.value > 4095 && params.value <= 12695", + "style": {"backgroundColor": "#aaa9ba"}, + }, + { + "condition": "params.value > 12695", + "style": {"backgroundColor": "#00b4ff"}, + }, + ] + } + + columnDefs = [ + {"field": "country"}, + {"field": "continent"}, + {"field": "year"}, + { + "field": "lifeExp", + "valueFormatter": {"function": "d3.format('.1f')(params.value)"}, + }, + { + "field": "gdpPercap", + "valueFormatter": {"function": "d3.format('$,.1f')(params.value)"}, + "cellStyle": cellStyle, + }, + { + "field": "pop", + "valueFormatter": {"function": "d3.format(',.0f')(params.value)"}, + }, + ] + + page = vm.Page( + title="Example of Modified Dash AG Grid", + components=[ + vm.AgGrid( + title="Modified Dash AG Grid", + figure=dash_ag_grid( + data_frame=df, + columnDefs=columnDefs, + defaultColDef={"resizable": False, "filter": False, "editable": True}, + ), + ) + ], + ) + + dashboard = vm.Dashboard(pages=[page]) + + Vizro().build(dashboard).run() + ``` + === "app.yaml" + ```yaml + # Still requires a .py to register data connector in Data Manager and parse yaml configuration + # See from_yaml example + pages: + - components: + - figure: + _target_: dash_ag_grid + data_frame: gapminder + columnDefs: + - field: country + - field: continent + - field: year + - field: lifeExp + valueFormatter: + function: "d3.format('.1f')(params.value)" + - field: gdpPercap + valueFormatter: + function: "d3.format('$,.1f')(params.value)" + cellStyle: + styleConditions: + - condition: params.value < 1045 + style: + backgroundColor: "#ff9222" + - condition: params.value >= 1045 && params.value <= 4095 + style: + backgroundColor: "#de9e75" + - condition: params.value > 4095 && params.value <= 12695 + style: + backgroundColor: "#aaa9ba" + - condition: params.value > 12695 + style: + backgroundColor: "#00b4ff" + - field: pop + type: rightAligned + valueFormatter: + function: "d3.format(',.0f')(params.value)" + defaultColDef: + resizable: false + filter: false + editable: true + title: Dash AG Grid + type: ag_grid + title: Example of a Dash AG Grid + ``` + === "Result" + [![AGGrid3]][AGGrid3] + + [AGGrid3]: ../../assets/user_guides/table/styled_aggrid.png + +If the available arguments are not sufficient, there is always the option to create a [custom AG Grid callable](custom-tables.md). + +## Dash DataTable + +Similar to AG Grid, the [Dash DataTable](https://dash.plotly.com/datatable) is an interactive table/grid component designed for viewing, editing, and exploring large datasets. + +In general, we recommend using [AG Grid](#ag-grid) for tables unless you have a particular reason to prefer Dash DataTable. + +The Vizro [`Table`][vizro.models.Table] model is based on the [Dash DataTable](https://dash.plotly.com/datatable). + +### Basic usage + +To add a [`Table`][vizro.models.Table] to your page, do the following: + +- Insert the [`Table`][vizro.models.Table] model into the `components` argument of the +[`Page`][vizro.models.Page] model. +- Enter the `dash_data_table` function under the `figure` argument (imported via `from vizro.tables import dash_data_table`). + The Vizro version of this table differs in one way from the original table: 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 DataTable](https://dash.plotly.com/datatable/reference) can be entered as keyword arguments. Note that we are @@ -63,7 +354,7 @@ setting some defaults for some of the arguments to help with styling. [Table]: ../../assets/user_guides/table/table.png -#### Styling and modifying the Dash DataTable +### Styling and modifying the Dash DataTable As mentioned above, all [parameters of the Dash DataTable](https://dash.plotly.com/datatable/reference) can be entered as keyword arguments. Below you can find an example of a styled table where some conditional formatting is applied. There are many more ways to alter the table beyond this showcase. @@ -193,4 +484,4 @@ an example of a styled table where some conditional formatting is applied. There [Table2]: ../../assets/user_guides/table/styled_table.png -To enhance existing tables, please see our How-to-guide on creating [custom tables](custom-tables.md). +If the available arguments are not sufficient, there is always the option to create a [custom Dash DataTable](custom-tables.md). diff --git a/vizro-core/examples/_dev/yaml_version/dashboard.yaml b/vizro-core/examples/_dev/yaml_version/dashboard.yaml index c085a85ec..30ee4a829 100644 --- a/vizro-core/examples/_dev/yaml_version/dashboard.yaml +++ b/vizro-core/examples/_dev/yaml_version/dashboard.yaml @@ -1,47 +1,42 @@ +# Still requires a .py to register data connector in Data Manager and parse yaml configuration +# See from_yaml example pages: - components: - figure: - _target_: line + _target_: dash_ag_grid data_frame: gapminder - x: year - y: lifeExp - color: continent - title: Graph 1 - type: graph - - figure: - _target_: scatter - data_frame: gapminder - x: gdpPercap - y: lifeExp - size: pop - color: continent - title: Graph 2 - type: graph - - figure: - _target_: box - data_frame: gapminder - x: continent - y: lifeExp - color: continent - title: Graph 3 - type: graph - - figure: - _target_: line - data_frame: gapminder - x: year - y: lifeExp - color: continent - title: Graph 4 - type: graph - - figure: - _target_: scatter - data_frame: gapminder - x: gdpPercap - y: lifeExp - size: pop - color: continent - title: Graph 5 - type: graph - layout: - grid: [[0, 1, 3, 4], [2, 2, 3, 4]] - title: Custom Layout - Advanced Example + columnDefs: + - field: country + - field: continent + - field: year + - field: lifeExp + valueFormatter: + function: "d3.format('.1f')(params.value)" + - field: gdpPercap + valueFormatter: + function: "d3.format('$,.1f')(params.value)" + cellStyle: + styleConditions: + - condition: params.value < 1045 + style: + backgroundColor: "#ff9222" + - condition: params.value >= 1045 && params.value <= 4095 + style: + backgroundColor: "#de9e75" + - condition: params.value > 4095 && params.value <= 12695 + style: + backgroundColor: "#aaa9ba" + - condition: params.value > 12695 + style: + backgroundColor: "#00b4ff" + - field: pop + type: rightAligned + valueFormatter: + function: "d3.format(',.0f')(params.value)" + defaultColDef: + resizable: false + filter: false + editable: true + title: Dash AG Grid + type: ag_grid + title: Example of a Dash AG Grid diff --git a/vizro-core/examples/demo/app.py b/vizro-core/examples/demo/app.py index 4d2d169b6..5fa97b690 100644 --- a/vizro-core/examples/demo/app.py +++ b/vizro-core/examples/demo/app.py @@ -8,7 +8,7 @@ from vizro import Vizro from vizro.actions import export_data, filter_interaction from vizro.models.types import capture -from vizro.tables import dash_data_table +from vizro.tables import dash_ag_grid gapminder = px.data.gapminder() gapminder_mean = ( @@ -401,14 +401,34 @@ def create_continent_summary(): def create_benchmark_analysis(): """Function returns a page to perform analysis on country level.""" - # Apply formatting to table columns - columns = [ - {"id": "country", "name": "country"}, - {"id": "continent", "name": "continent"}, - {"id": "year", "name": "year"}, - {"id": "lifeExp", "name": "lifeExp", "type": "numeric", "format": {"specifier": ",.1f"}}, - {"id": "gdpPercap", "name": "gdpPercap", "type": "numeric", "format": {"specifier": "$,.2f"}}, - {"id": "pop", "name": "pop", "type": "numeric", "format": {"specifier": ",d"}}, + # Apply formatting to grid columns + cellStyle = { + "styleConditions": [ + { + "condition": "params.value < 1045", + "style": {"backgroundColor": "#ff9222"}, + }, + { + "condition": "params.value >= 1045 && params.value <= 4095", + "style": {"backgroundColor": "#de9e75"}, + }, + { + "condition": "params.value > 4095 && params.value <= 12695", + "style": {"backgroundColor": "#aaa9ba"}, + }, + { + "condition": "params.value > 12695", + "style": {"backgroundColor": "#00b4ff"}, + }, + ] + } + columnsDefs = [ + {"field": "country"}, + {"field": "continent"}, + {"field": "year"}, + {"field": "lifeExp", "cellDataType": "numeric"}, + {"field": "gdpPercap", "cellDataType": "dollar", "cellStyle": cellStyle}, + {"field": "pop"}, ] page_country = vm.Page( @@ -416,40 +436,9 @@ def create_benchmark_analysis(): description="Discovering how the metrics differ for each country and export data for further investigation", layout=vm.Layout(grid=[[0, 1]] * 5 + [[2, -1]], col_gap="32px", row_gap="60px"), components=[ - vm.Table( + vm.AgGrid( title="Click on a cell in country column:", - figure=dash_data_table( - id="dash_data_table_country", - data_frame=gapminder, - columns=columns, - page_size=10, - style_data_conditional=[ - { - "if": {"filter_query": "{gdpPercap} < 1045", "column_id": "gdpPercap"}, - "backgroundColor": "#ff9222", - }, - { - "if": { - "filter_query": "{gdpPercap} >= 1045 && {gdpPercap} <= 4095", - "column_id": "gdpPercap", - }, - "backgroundColor": "#de9e75", - }, - { - "if": { - "filter_query": "{gdpPercap} > 4095 && {gdpPercap} <= 12695", - "column_id": "gdpPercap", - }, - "backgroundColor": "#aaa9ba", - }, - { - "if": {"filter_query": "{gdpPercap} > 12695", "column_id": "gdpPercap"}, - "backgroundColor": "#00b4ff", - }, - ], - sort_action="native", - style_cell={"textAlign": "left"}, - ), + figure=dash_ag_grid(id="dash_ag_grid_country", data_frame=gapminder, columnDefs=columnsDefs), actions=[vm.Action(function=filter_interaction(targets=["line_country"]))], ), vm.Graph( diff --git a/vizro-core/examples/features/app.py b/vizro-core/examples/features/app.py index 8cca2577c..9c0c62d45 100644 --- a/vizro-core/examples/features/app.py +++ b/vizro-core/examples/features/app.py @@ -11,7 +11,7 @@ from vizro import Vizro from vizro.actions import export_data, filter_interaction from vizro.models.types import capture -from vizro.tables import dash_data_table +from vizro.tables import dash_ag_grid, dash_data_table iris = px.data.iris() gapminder = px.data.gapminder() @@ -99,6 +99,17 @@ controls=[vm.Filter(column="species", selector=vm.Dropdown(title="Species"))], ) +ag_grid = vm.Page( + title="AG Grid", + components=[ + vm.AgGrid( + title="Dash AG Grid", + figure=dash_ag_grid(data_frame=gapminder_2007), + ) + ], + controls=[vm.Filter(column="continent")], +) + table = vm.Page( title="Table", components=[ @@ -635,7 +646,7 @@ def my_custom_action(t: int): ) # DASHBOARD ------------------------------------------------------------------- -components = [graphs, table, cards, button, containers, tabs] +components = [graphs, ag_grid, table, cards, button, containers, tabs] controls = [filters, parameters, selectors] actions = [export_data_action, chart_interaction] extensions = [custom_charts, custom_tables, custom_components, custom_actions] @@ -650,7 +661,7 @@ def my_custom_action(t: int): vm.NavLink( label="Features", pages={ - "Components": ["Graphs", "Table", "Cards", "Button", "Containers", "Tabs"], + "Components": ["Graphs", "AG Grid", "Table", "Cards", "Button", "Containers", "Tabs"], "Controls": ["Filters", "Parameters", "Selectors"], "Actions": ["Export data", "Chart interaction"], "Extensions": ["Custom Charts", "Custom Tables", "Custom Components", "Custom Actions"], diff --git a/vizro-core/examples/features/yaml_version/dashboard.yaml b/vizro-core/examples/features/yaml_version/dashboard.yaml index 4b1be1cc1..21123b885 100644 --- a/vizro-core/examples/features/yaml_version/dashboard.yaml +++ b/vizro-core/examples/features/yaml_version/dashboard.yaml @@ -71,6 +71,16 @@ pages: - column: continent type: filter title: Table + - components: + - figure: + _target_: dash_ag_grid + data_frame: gapminder_2007 + title: Dash AG Grid + type: ag_grid + controls: + - column: continent + type: filter + title: AG Grid - components: - text: | # Header level 1

@@ -444,6 +454,7 @@ navigation: pages: Components: - Graphs + - AG Grid - Table - Cards - Button