diff --git a/README.md b/README.md index 222a9ec67ea3c955e749fed11b4d1ffdf62d84ae..25a7ae44df1471acd812bb03df7b29a537d7bfcd 100644 --- a/README.md +++ b/README.md @@ -47,68 +47,66 @@ Credits and sources: The dashboard is still in development. Below is an overview of the chart types for which a completed page is available. -Sure, here's the table with all columns aligned for better readability: - -| Chart Type | Status | Category | Credits & sources | API | -| --------------------- | ------ | ------------------------ | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Arc | ❌ | Part-to-whole | | | -| Area | ✅ | Time | [Filled area plot with px](https://plotly.com/python/filled-area-plots/) | [px.area](https://plotly.com/python-api-reference/generated/plotly.express.area) | -| Bar | ✅ | Magnitude | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) | -| Barcode | ❌ | Distribution | | | -| Beeswarm | ❌ | Distribution | | | -| Boxplot | ✅ | Distribution | [Box plot with px](https://plotly.com/python/box-plots/) | [px.box](https://plotly.github.io/plotly.py-docs/generated/plotly.express.box) | -| Bubble | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) | -| Bubble map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) | -| Bubble timeline | ❌ | Time | | | -| Bullet | ❌ | Magnitude | | | -| Bump | ❌ | Ranking | | | -| Butterfly | ✅ | Deviation, Distribution | [Pyramid charts in Plotly](https://plotly.com/python/v3/population-pyramid-charts/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) | -| Chord | ❌ | Flow | | | -| Choropleth | ✅ | Spatial | [Choropleth map with px](https://plotly.com/python/choropleth-maps/) | [px.choropleth](https://plotly.github.io/plotly.py-docs/generated/plotly.express.choropleth.html) | -| Column | ✅ | Magnitude, Time | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) | -| Column and line | ✅ | Correlation, Time | [Multiple chart types in Plotly](https://plotly.com/python/graphing-multiple-chart-types/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) and [go.Scatter](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Scatter.html) | -| Connected scatter | ✅ | Correlation, Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) | -| Cumulative curve | ❌ | Distribution | | | -| Diverging bar | ✅ | Deviation | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) | -| Diverging stacked bar | ❌ | Deviation | | | -| Donut | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) | -| Dot map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) | -| Dumbbell | ✅ | Distribution | [Dumbbell plots in Plotly](https://community.plotly.com/t/how-to-make-dumbbell-plots-in-plotly-python/47762) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter.html) and [add_shape](https://plotly.com/python/shapes/) | -| Fan | ❌ | Time | | | -| Flow map | ❌ | Spatial | | | -| Funnel | ✅ | Part-to-whole | [Funnel plot with px](https://plotly.com/python/funnel-charts/) | [px.funnel](https://plotly.com/python/funnel-charts/) | -| Gantt | ✅ | Time | [Gantt chart with px](https://plotly.com/python/gantt/) | [px.timeline](https://plotly.com/python-api-reference/generated/plotly.express.timeline.html) | -| Gridplot | ❌ | Part-to-whole | | | -| Heatmap | ✅ | Time | [Heatmaps with px](https://plotly.com/python/heatmaps/) | [px.density_heatmap](https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html) | -| Correlation matrix | ❌ | Correlation | | | -| Histogram | ✅ | Distribution | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | -| Line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) | -| Lollipop | ❌ | Ranking, Magnitude | | | -| Marimekko | ❌ | Magnitude, Part-to-whole | | | -| Network | ❌ | Flow | | | -| Ordered bar | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) | -| Ordered bubble | ❌ | Ranking | | | -| Ordered column | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) | -| Paired bar | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | -| Paired column | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | -| Parallel coordinates | ✅ | Magnitude | [Parallel coordinates plot with px](https://plotly.com/python/parallel-coordinates-plot/) | [px.parallel_coordinates](https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html) | -| Pictogram | ❌ | Magnitude | | | -| Pie | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) | -| Radar | ✅ | Magnitude | [Radar chart with px](https://plotly.com/python/radar-chart/) | [px.line_polar](https://plotly.com/python-api-reference/generated/plotly.express.line_polar) | -| Radial | ❌ | Magnitude | | | -| Sankey | ✅ | Flow | [Sankey diagram in Plotly](https://plotly.com/python/sankey-diagram/) | [go.Sankey](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Sankey.html) | -| Scatter | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) | -| Scatter matrix | ✅ | Correlation | [Scatter matrix with px](https://plotly.com/python/splom/) | [px.scatter_matrix](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_matrix.html) | -| Slope | ❌ | Ranking, Time | | | -| Sparkline | ❌ | Time | | | -| Stacked bar | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | -| Stacked column | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | -| Stepped line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) | -| Surplus deficit line | ❌ | Deviation | | | -| Treemap | ✅ | Part-to-whole | [Treemap with px](https://plotly.com/python/treemaps/) | [px.treemap](https://plotly.com/python-api-reference/generated/plotly.express.treemap.html) | -| Venn | ❌ | Part-to-whole | | | -| Violin | ✅ | Distribution | [Violin plot with px](https://plotly.com/python/violin/) | [px.violin](https://plotly.com/python-api-reference/generated/plotly.express.violin.html) | -| Waterfall | ✅ | Part-to-whole, Flow | [Waterfall charts in Plotly](https://plotly.com/python/waterfall-charts/) | [go.Waterfall](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Waterfall.html) | +| Chart Type | Status | Category | Credits & sources | API | +| --------------------- | ------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Arc | ❌ | Part-to-whole | | | +| Area | ✅ | Time | [Filled area plot with px](https://plotly.com/python/filled-area-plots/) | [px.area](https://plotly.com/python-api-reference/generated/plotly.express.area) | +| Bar | ✅ | Magnitude | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) | +| Barcode | ❌ | Distribution | | | +| Beeswarm | ❌ | Distribution | | | +| Boxplot | ✅ | Distribution | [Box plot with px](https://plotly.com/python/box-plots/) | [px.box](https://plotly.github.io/plotly.py-docs/generated/plotly.express.box) | +| Bubble | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) | +| Bubble map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) | +| Bubble timeline | ❌ | Time | | | +| Bullet | ❌ | Magnitude | | | +| Bump | ❌ | Ranking | | | +| Butterfly | ✅ | Deviation, Distribution | [Pyramid charts in Plotly](https://plotly.com/python/v3/population-pyramid-charts/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) | +| Chord | ❌ | Flow | | | +| Choropleth | ✅ | Spatial | [Choropleth map with px](https://plotly.com/python/choropleth-maps/) | [px.choropleth](https://plotly.github.io/plotly.py-docs/generated/plotly.express.choropleth.html) | +| Column | ✅ | Magnitude, Time | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) | +| Column and line | ✅ | Correlation, Time | [Multiple chart types in Plotly](https://plotly.com/python/graphing-multiple-chart-types/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) and [go.Scatter](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Scatter.html) | +| Connected scatter | ✅ | Correlation, Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) | +| Cumulative curve | ❌ | Distribution | | | +| Diverging bar | ✅ | Deviation | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) | +| Diverging stacked bar | ✅ | Deviation | [Plotly forum - diverging stacked bar](https://community.plotly.com/t/need-help-in-making-diverging-stacked-bar-charts/34023/2) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) | +| Donut | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) | +| Dot map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) | +| Dumbbell | ✅ | Distribution | [Dumbbell plots in Plotly](https://community.plotly.com/t/how-to-make-dumbbell-plots-in-plotly-python/47762) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter.html) and [add_shape](https://plotly.com/python/shapes/) | +| Fan | ❌ | Time | | | +| Flow map | ❌ | Spatial | | | +| Funnel | ✅ | Part-to-whole | [Funnel plot with px](https://plotly.com/python/funnel-charts/) | [px.funnel](https://plotly.com/python/funnel-charts/) | +| Gantt | ✅ | Time | [Gantt chart with px](https://plotly.com/python/gantt/) | [px.timeline](https://plotly.com/python-api-reference/generated/plotly.express.timeline.html) | +| Gridplot | ❌ | Part-to-whole | | | +| Heatmap | ✅ | Time | [Heatmaps with px](https://plotly.com/python/heatmaps/) | [px.density_heatmap](https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html) | +| Correlation matrix | ❌ | Correlation | | | +| Histogram | ✅ | Distribution | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | +| Line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) | +| Lollipop | ❌ | Ranking, Magnitude | | | +| Marimekko | ❌ | Magnitude, Part-to-whole | | | +| Network | ❌ | Flow | | | +| Ordered bar | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) | +| Ordered bubble | ❌ | Ranking | | | +| Ordered column | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) | +| Paired bar | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | +| Paired column | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | +| Parallel coordinates | ✅ | Magnitude | [Parallel coordinates plot with px](https://plotly.com/python/parallel-coordinates-plot/) | [px.parallel_coordinates](https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html) | +| Pictogram | ❌ | Magnitude | | | +| Pie | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) | +| Radar | ✅ | Magnitude | [Radar chart with px](https://plotly.com/python/radar-chart/) | [px.line_polar](https://plotly.com/python-api-reference/generated/plotly.express.line_polar) | +| Radial | ❌ | Magnitude | | | +| Sankey | ✅ | Flow | [Sankey diagram in Plotly](https://plotly.com/python/sankey-diagram/) | [go.Sankey](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Sankey.html) | +| Scatter | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) | +| Scatter matrix | ✅ | Correlation | [Scatter matrix with px](https://plotly.com/python/splom/) | [px.scatter_matrix](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_matrix.html) | +| Slope | ❌ | Ranking, Time | | | +| Sparkline | ❌ | Time | | | +| Stacked bar | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | +| Stacked column | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) | +| Stepped line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) | +| Surplus deficit line | ❌ | Deviation | | | +| Treemap | ✅ | Part-to-whole | [Treemap with px](https://plotly.com/python/treemaps/) | [px.treemap](https://plotly.com/python-api-reference/generated/plotly.express.treemap.html) | +| Venn | ❌ | Part-to-whole | | | +| Violin | ✅ | Distribution | [Violin plot with px](https://plotly.com/python/violin/) | [px.violin](https://plotly.com/python-api-reference/generated/plotly.express.violin.html) | +| Waterfall | ✅ | Part-to-whole, Flow | [Waterfall charts in Plotly](https://plotly.com/python/waterfall-charts/) | [go.Waterfall](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Waterfall.html) | ## How to contribute diff --git a/app.py b/app.py index 4ea56cd73d8b4d963f2d299a6074f45b6b9e93f6..c465de0ed69e357cbe3a1ffe9c2cb29ef5441494 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,6 @@ """App configuration for dashboard.""" -from typing import List, Union +from typing import Union import vizro.models as vm from chart_groups import ALL_CHART_GROUP, CHART_GROUPS, ChartGroup, IncompletePage @@ -60,7 +60,7 @@ def make_homepage_container(chart_group: ChartGroup) -> vm.Container: ) -def _remove_duplicates(pages: List[Union[vm.Page, IncompletePage]]) -> List[Union[vm.Page, IncompletePage]]: +def _remove_duplicates(pages: list[Union[vm.Page, IncompletePage]]) -> list[Union[vm.Page, IncompletePage]]: # Deduplicate pages that have the same title. Using reversed means that the page that is kept is the first one # in the dashboard. This will be the one that the card on the homepage links to. return list({page.title: page for page in reversed(pages)}.values()) @@ -111,4 +111,4 @@ app = Vizro().build(dashboard) server = app.dash.server if __name__ == "__main__": - app.run() + app.run(port=8051) diff --git a/assets/css/custom.css b/assets/css/custom.css index e96b472c3da7896d632d0898cfa4eca5dd7b0505..5c0a89a5737838934f658c344dca627bfdf6ed16 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -10,22 +10,36 @@ img[src*="#chart-icon"] { width: 100%; } +.open-in-new { + font-size: inherit; + margin-left: 4px; + vertical-align: middle; +} + .code-clipboard { + float: right; font-size: 20px; - position: absolute; - right: 14px; - top: 12px; +} + +.code-clipboard pre { + font-family: monospace; + margin-bottom: 12px; } .code-clipboard-container { background: var(--surfaces-bg-card); - font-family: monospace; max-height: 500px; overflow: auto; padding: 1rem; position: relative; } +.code-clipboard-container .pycafe-link, +.code-clipboard-container .pycafe-link:focus { + line-height: unset; + margin-bottom: 12px; +} + .code-clipboard-container::-webkit-scrollbar-thumb { border-color: var(--surfaces-bg-card); } @@ -73,10 +87,6 @@ img[src*="#chart-icon"] { margin: 0; } -.intro-text p a { - font-size: inherit; -} - .intro-text ul:last-of-type { margin-bottom: 0; } diff --git a/chart_groups.py b/chart_groups.py index 2e6f4f228f3153cf368eb16a6c0d1b6aa2f34213..2896306f8e3c42ee5b27d07743ab5effa6d041c7 100644 --- a/chart_groups.py +++ b/chart_groups.py @@ -2,7 +2,6 @@ import itertools from dataclasses import dataclass -from typing import List import pages.correlation import pages.deviation @@ -36,8 +35,8 @@ class ChartGroup: """Represents a group of charts like "Deviation".""" name: str - pages: List[vm.Page] - incomplete_pages: List[IncompletePage] + pages: list[vm.Page] + incomplete_pages: list[IncompletePage] intro_text: str icon: str = "" # ALL_CHART_GROUP is the only one that doesn't require an icon. @@ -51,7 +50,6 @@ deviation_chart_group = ChartGroup( name="Deviation", pages=pages.deviation.pages, incomplete_pages=[ - IncompletePage("Diverging stacked bar"), IncompletePage(title="Surplus deficit filled line"), ], icon="Contrast Square", diff --git a/custom_charts.py b/custom_charts.py index 82b021eac35575914c163e6177c9266e10950d93..7e1f26948f5eb3b7f8f636d724f5aa7e03dc6be4 100644 --- a/custom_charts.py +++ b/custom_charts.py @@ -1,6 +1,6 @@ """Contains custom charts used inside the dashboard.""" -from typing import List +from typing import Union import pandas as pd import vizro.plotly.express as px @@ -13,181 +13,185 @@ from vizro.models.types import capture # it can get out of sync. But probably we don't want the docstrings in the short code snippet. # Ultimately these charts will probably move to vizro.charts anyway. @capture("graph") -def butterfly(data_frame: pd.DataFrame, x1: str, x2: str, y: str) -> go.Figure: - """Creates a custom butterfly chart using Plotly's go.Figure. +def butterfly(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + """Creates a butterfly chart based on px.bar. A butterfly chart is a type of bar chart where two sets of bars are displayed back-to-back, often used to compare two sets of data. Args: - data_frame (pd.DataFrame): The data source for the chart. - x1 (str): The name of the column in the data frame for the first set of bars (negative values). - x2 (str): The name of the column in the data frame for the second set of bars (positive values). - y (str): The name of the column in the data frame for the y-axis (categories). + data_frame: DataFrame for the chart. Can be long form or wide form. + See https://plotly.com/python/wide-form/. + **kwargs: Keyword arguments to pass into px.bar (e.g. x, y, labels). + See https://plotly.com/python-api-reference/generated/plotly.express.bar.html. Returns: - go.Figure: A Plotly Figure object representing the butterfly chart. + go.Figure: Butterfly chart. """ - fig = go.Figure() - fig.add_trace( - go.Bar( - x=-data_frame[x1], - y=data_frame[y], - orientation="h", - name=x1, - ) - ) - fig.add_trace( - go.Bar( - x=data_frame[x2], - y=data_frame[y], - orientation="h", - name=x2, - ) + fig = px.bar(data_frame, **kwargs) + + orientation = fig.data[0].orientation + x_or_y = "x" if orientation == "h" else "y" + + # Create new x or y axis with scale reversed (so going from 0 at the midpoint outwards) to do back-to-back bars. + fig.update_traces({f"{x_or_y}axis": f"{x_or_y}2"}, selector=1) + fig.update_layout({f"{x_or_y}axis2": fig.layout[f"{x_or_y}axis"]}) + fig.update_layout( + {f"{x_or_y}axis": {"autorange": "reversed", "domain": [0, 0.5]}, f"{x_or_y}axis2": {"domain": [0.5, 1]}} ) - fig.update_layout(barmode="relative") + + if orientation == "h": + fig.add_vline(x=0, line_width=2, line_color="grey") + else: + fig.add_hline(y=0, line_width=2, line_color="grey") + return fig @capture("graph") -def sankey(data_frame: pd.DataFrame, source: str, target: str, value: str, labels: List[str]) -> go.Figure: - """Creates a custom sankey chart using Plotly's `go.Sankey`. +def sankey(data_frame: pd.DataFrame, source: str, target: str, value: str, labels: list[str]) -> go.Figure: + """Creates a Sankey chart based on go.Sankey. A Sankey chart is a type of flow diagram where the width of the arrows is proportional to the flow rate. It is used to visualize the flow of resources or data between different stages or categories. - Args: - data_frame (pd.DataFrame): The data source for the chart. - source (str): The name of the column in the data frame for the source nodes. - target (str): The name of the column in the data frame for the target nodes. - value (str): The name of the column in the data frame for the values representing the flow between nodes. - labels (List[str]): A list of labels for the nodes. - - Returns: - go.Figure: A Plotly Figure object representing the Sankey chart. - For detailed information on additional parameters and customization, refer to the Plotly documentation: https://plotly.com/python/reference/sankey/ + Args: + data_frame: DataFrame for the chart. + source: The name of the column in data_frame for source nodes. + target: The name of the column in data_frame for target nodes. + value: The name of the column in data_frame for the values representing the flow between nodes. + labels: A list of labels for the nodes. + + Returns: + go.Figure: Sankey chart. """ - fig = go.Figure( - data=[ - go.Sankey( - node={ - "pad": 16, - "thickness": 16, - "label": labels, - }, - link={ - "source": data_frame[source], - "target": data_frame[target], - "value": data_frame[value], - "label": labels, - "color": "rgba(205, 209, 228, 0.4)", - }, - ) - ] + return go.Figure( + data=go.Sankey( + node={ + "pad": 16, + "thickness": 16, + "label": labels, + }, + link={ + "source": data_frame[source], + "target": data_frame[target], + "value": data_frame[value], + "label": labels, + "color": "rgba(205, 209, 228, 0.4)", + }, + ), + layout={"barmode": "relative"}, ) - fig.update_layout(barmode="relative") - return fig @capture("graph") -def column_and_line(data_frame: pd.DataFrame, x: str, y_column: str, y_line: str) -> go.Figure: - """Creates a combined column and line chart using Plotly. +def column_and_line( + data_frame: pd.DataFrame, + x: Union[str, pd.Series, list[str], list[pd.Series]], + y_column: Union[str, pd.Series, list[str], list[pd.Series]], + y_line: Union[str, pd.Series, list[str], list[pd.Series]], +) -> go.Figure: + """Creates a combined column and line chart based on px.bar and px.line. This function generates a chart with a bar graph for one variable (y-axis 1) and a line graph for another variable (y-axis 2), sharing the same x-axis. The y-axes for the bar and line graphs are synchronized and overlaid. Args: - data_frame (pd.DataFrame): The data source for the chart. - x (str): The column name to be used for the x-axis. - y_column (str): The column name to be used for the y-axis 1, representing the column chart. - y_line (str): The column name to be used for the y-axis 2, representing the line chart. + data_frame: DataFrame for the chart. Can be long form or wide form. + See https://plotly.com/python/wide-form/. + x: Either a name of a column in data_frame, or a pandas Series or array_like object. + y_column: Either a name of a column in data_frame, or a pandas Series or array_like object. + y_line: Either a name of a column in data_frame, or a pandas Series or array_like object. Returns: - go.Figure: : A Plotly Figure object representing the combined column and line chart. + go.Figure: Combined column and line chart. """ - fig = make_subplots(specs=[[{"secondary_y": True}]]) + # We use px.bar and px.line so that we get the plotly express hoverdata, axes titles etc. Bar is used arbitrarily + # selected as the "base" plot and then line added on top of it. This means manually incrementing + # color_discrete_sequence for the line plot so that the colors are not the same for bar and line. + bar = px.bar(data_frame, x=x, y=y_column) + fig = make_subplots(figure=bar, specs=[[{"secondary_y": True}]]) - fig.add_trace( - go.Bar(x=data_frame[x], y=data_frame[y_column], name=y_column), - secondary_y=False, + line = px.line( + data_frame, + x=x, + y=y_line, + markers=True, + color_discrete_sequence=fig.layout.template.layout.colorway[len(bar.data) :], ) - fig.add_trace( - go.Scatter(x=data_frame[x], y=data_frame[y_line], name=y_line), - secondary_y=True, - ) + for trace in line.data: + fig.add_trace(trace, secondary_y=True) - fig.update_layout( - xaxis={"type": "category", "title": x}, - yaxis={"tickmode": "sync", "title": y_column}, - yaxis2={"tickmode": "sync", "overlaying": "y", "title": y_line}, - ) + fig.update_layout(yaxis2={"tickmode": "sync", "overlaying": "y", "title": line.layout.yaxis.title}) return fig @capture("graph") -def categorical_column(data_frame: pd.DataFrame, x: str, y: str): - """Creates a column chart where the x-axis values are converted to category type.""" - fig = px.bar( - data_frame, - x=x, - y=y, - ) +def categorical_column(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + """Creates categorical bar chart based on px.bar. + + Args: + data_frame: DataFrame for the chart. Can be long form or wide form. + See https://plotly.com/python/wide-form/. + **kwargs: Keyword arguments to pass into px.bar (e.g. x, y, labels). + See https://plotly.com/python-api-reference/generated/plotly.express.bar.html. + + Returns: + go.Figure: Categorical column chart. + + """ + fig = px.bar(data_frame, **kwargs) # So ticks are aligned with bars when xaxes values are numbers (e.g. years) fig.update_xaxes(type="category") return fig @capture("graph") -def waterfall(data_frame: pd.DataFrame, x: str, y: str, measure: List[str]) -> go.Figure: - """Creates a waterfall chart using Plotly's `go.Waterfall`. +def waterfall(data_frame: pd.DataFrame, x: str, y: str, measure: list[str]) -> go.Figure: + """Creates a waterfall chart based on go.Waterfall. A Waterfall chart visually breaks down the cumulative effect of sequential positive and negative values, showing how each value contributes to the total. - Args: - data_frame (pd.DataFrame): The data source for the chart. - x (str): Column name in `data_frame` for x-axis values. - y (str): Column name in `data_frame` for y-axis values. - measure (List[str]): List specifying the type of each bar, can be "relative", "total", or "absolute". - - Returns: - go.Figure: A Plotly Figure object representing the Waterfall chart. - For additional parameters and customization options, see the Plotly documentation: https://plotly.com/python/reference/waterfall/ + Args: + data_frame: TDataFrame for the chart. + x: Column name in data_frame for x-axis values. + y: Column name in data_frame for y-axis values. + measure: List specifying the type of each bar, can be "relative", "total", or "absolute". + + Returns: + go.Figure: Waterfall chart. """ - fig = go.Figure( - go.Waterfall( - x=data_frame[x], - y=data_frame[y], - measure=data_frame[measure], - ) + return go.Figure( + data=go.Waterfall(x=data_frame[x], y=data_frame[y], measure=data_frame[measure]), + layout={"showlegend": False}, ) - fig.update_layout(showlegend=False) - return fig @capture("graph") -def radar(data_frame, **kwargs) -> go.Figure: - """Creates a radar chart using Plotly's `line_polar`. +def radar(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + """Creates a radar chart based on px.line_polar. A radar chart is a type of data visualization in which there are three or more variables represented on axes that originate from the same central point. Args: - data_frame (pd.DataFrame): The data source for the chart. - **kwargs: Keyword arguments that can be passed into Plotly's line_polar (i.e. r, theta, etc.) + data_frame: DataFrame for the chart. + **kwargs: Keyword arguments to pass into px.line_polar (e.g. r, theta). + See https://plotly.com/python-api-reference/generated/plotly.express.line_polar.html. Returns: - go.Figure: A Plotly Figure object representing the radar chart. + go.Figure: A Plotly Figure object of the radar chart. """ fig = px.line_polar(data_frame, **kwargs) @@ -196,40 +200,107 @@ def radar(data_frame, **kwargs) -> go.Figure: @capture("graph") -def dumbbell(data_frame: pd.DataFrame, x: str, y: str, color: str) -> go.Figure: - """Creates a dumbbell chart using Plotly's `px.scatter` and `add_shape`. +def dumbbell(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + """Creates a dumbbell chart based on px.scatter. A dumbbell plot is a type of dot plot where the points, displaying different groups, are connected with a straight line. They are ideal for illustrating differences or gaps between two points. + Inspired by: https://community.plotly.com/t/how-to-make-dumbbell-plots-in-plotly-python/47762 + Args: - data_frame (pd.DataFrame): The data source for the chart. - x (str): Column name in `data_frame` for x-axis values. - y (str): Column name in `data_frame` for y-axis values. - color (str): Column name in `data_frame` used for coloring the markers. + data_frame: DataFrame for the chart. Can be long form or wide form. + See https://plotly.com/python/wide-form/. + **kwargs: Keyword arguments to pass into px.scatter (e.g. x, y, labels). + See https://plotly.com/python-api-reference/generated/plotly.scatter.html. Returns: - go.Figure: A Plotly Figure object representing the dumbbell chart. - - Inspired by: https://community.plotly.com/t/how-to-make-dumbbell-plots-in-plotly-python/47762 - + go.Figure: Dumbbell chart. """ - # Add two dots to plot - fig = px.scatter(data_frame, y=y, x=x, color=color) - - # Add lines between dots - for y_value, group in data_frame.groupby(y): + fig = px.scatter(data_frame, **kwargs) + + orientation = fig.data[0].orientation + x_or_y = "x" if orientation == "h" else "y" + y_or_x = "y" if orientation == "h" else "x" + + # Add lines between every pair of points. + for x_or_y_0, x_or_y_1, y_or_x_0, y_or_x_1 in zip( + fig.data[0][x_or_y], + fig.data[1][x_or_y], + fig.data[0][y_or_x], + fig.data[1][y_or_x], + ): fig.add_shape( + **{f"{x_or_y}0": x_or_y_0, f"{x_or_y}1": x_or_y_1, f"{y_or_x}0": y_or_x_0, f"{y_or_x}1": y_or_x_1}, type="line", layer="below", - y0=y_value, - y1=y_value, - x0=group[x].min(), - x1=group[x].max(), line_color="grey", line_width=3, ) - # Increase size of dots fig.update_traces(marker_size=12) return fig + + +@capture("graph") +def diverging_stacked_bar(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + """Creates a diverging stacked bar chart based on px.bar. + + This type of chart is a variant of the standard stacked bar chart, with bars aligned on a central baseline to + show both positive and negative values. Each bar is segmented to represent different categories. + + This function is not suitable for diverging stacked bar charts that include a neutral category. The first half of + bars plotted are assumed to be negative ("Disagree") and the second half are assumed to be positive ("Agree"). + + Inspired by: https://community.plotly.com/t/need-help-in-making-diverging-stacked-bar-charts/34023 + + Args: + data_frame: DataFrame for the chart. Can be long form or wide form. + See https://plotly.com/python/wide-form/. + **kwargs: Keyword arguments to pass into px.bar (e.g. x, y, labels). + See https://plotly.com/python-api-reference/generated/plotly.express.bar.html. + + Returns: + go.Figure: Diverging stacked bar chart. + """ + fig = px.bar(data_frame, **kwargs) + + # Fix legend position according to the order of traces. This ensures that "Strongly disagree" comes before + # "Disagree". + for i, trace in enumerate(fig.data): + trace.update(legendrank=i) + + if "color_discrete_sequence" not in kwargs and "color_discrete_map" not in kwargs: + # Make a discrete diverging colorscale by sampling the right number of colors. + # Need to explicitly convert colorscale to list of lists due to plotly bug/inconsistency: + # https://github.com/plotly/plotly.py/issues/4808 + colorscale = [list(x) for x in fig.layout.template.layout.colorscale.diverging] + colors = px.colors.sample_colorscale(colorscale, len(fig.data), 0.2, 0.8) + for trace, color in zip(fig.data, colors): + trace.update(marker_color=color) + + # Plotly draws traces in order they appear in fig.data, starting from x=0 and then stacking outwards. + # We need negative traces to be ordered so that "Disagree" comes before "Strongly disagree", so reverse the + # order of first half of traces. + mutable_traces = list(fig.data) + mutable_traces[: len(fig.data) // 2] = reversed(fig.data[: len(fig.data) // 2]) + fig.data = mutable_traces + + # Create new x or y axis with scale reversed (so going from 0 at the midpoint outwards) to do negative bars. + orientation = fig.data[0].orientation + x_or_y = "x" if orientation == "h" else "y" + + for trace_idx in range(len(fig.data) // 2): + fig.update_traces({f"{x_or_y}axis": f"{x_or_y}2"}, selector=trace_idx) + + fig.update_layout({f"{x_or_y}axis2": fig.layout[f"{x_or_y}axis"]}) + fig.update_layout( + {f"{x_or_y}axis": {"autorange": "reversed", "domain": [0, 0.5]}, f"{x_or_y}axis2": {"domain": [0.5, 1]}} + ) + + if orientation == "h": + fig.add_vline(x=0, line_width=2, line_color="grey") + else: + fig.add_hline(y=0, line_width=2, line_color="grey") + + return fig diff --git a/custom_components.py b/custom_components.py index 26ec8e0e4a9d1a7a55e2378bae2c500e407cfe7a..3105cdac8448058b3451fe62949e79dc874f2323 100644 --- a/custom_components.py +++ b/custom_components.py @@ -11,31 +11,38 @@ try: except ImportError: # pragma: no cov from pydantic import Field +from urllib.parse import quote + class CodeClipboard(vm.VizroBaseModel): """Code snippet with a copy to clipboard button.""" type: Literal["code_clipboard"] = "code_clipboard" code: str + mode: Literal["vizro", "plotly"] language: str = "" def build(self): """Returns the code clipboard component inside an accordion.""" markdown_code = "\n".join([f"```{self.language}", self.code, "```"]) - return dbc.Accordion( + + pycafe_link = dbc.Button( + [ + "Edit code live on PyCafe", + html.Span("open_in_new", className="material-symbols-outlined open-in-new"), + ], + href=f"https://py.cafe/snippet/vizro/v1#code={quote(self.code)}", + target="_blank", + className="pycafe-link", + ) + + return html.Div( [ - dbc.AccordionItem( - html.Div( - [ - dcc.Markdown(markdown_code, id=self.id), - dcc.Clipboard(target_id=self.id, className="code-clipboard"), - ], - className="code-clipboard-container", - ), - title="SHOW CODE", - ) + pycafe_link if self.mode == "vizro" else None, + dcc.Clipboard(target_id=self.id, className="code-clipboard"), + dcc.Markdown(markdown_code, id=self.id), ], - start_collapsed=False, + className="code-clipboard-container", ) @@ -68,4 +75,4 @@ class FlexContainer(vm.Container): vm.Container.add_type("components", FlexContainer) vm.Container.add_type("components", Markdown) -vm.Page.add_type("components", CodeClipboard) +vm.Container.add_type("components", CodeClipboard) diff --git a/pages/__init__.py b/pages/__init__.py index 3fcfb366d1c8212ffb3c13f90a8bd78c04c260b9..363f727fb380aba5d6ec2c05d24b7839369cb350 100644 --- a/pages/__init__.py +++ b/pages/__init__.py @@ -1,5 +1 @@ # TODO: eventually deduplicate page generation into a function rather than copying and pasting across files? -# TODO: think about the best way to do code examples, e.g. -# - do we want full dashboard example or plot-only example? -# - or both? Could be done using a toggle switch or multiple tabs. -# - a link to PyCafe showing the dashboard code? diff --git a/pages/_factories.py b/pages/_factories.py index 37ea1cf89fa20c746eab856170c14b95c68226f8..97b4615b585254951b86af70fb28bfc0dac34da1 100644 --- a/pages/_factories.py +++ b/pages/_factories.py @@ -5,10 +5,9 @@ each chart type used in different groups. """ import vizro.models as vm -import vizro.plotly.express as px -from custom_charts import butterfly, column_and_line, waterfall -from pages._pages_utils import PAGE_GRID, ages, gapminder, make_code_clipboard_from_py_file, waterfall_data +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import butterfly, column_and_line, connected_scatter, waterfall def butterfly_factory(group: str): @@ -37,8 +36,19 @@ def butterfly_factory(group: str): categories. """ ), - vm.Graph(figure=butterfly(ages, x1="Male", x2="Female", y="Age")), - make_code_clipboard_from_py_file("butterfly.py"), + vm.Graph(figure=butterfly.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("butterfly.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("butterfly.py", mode="plotly")], + ), + ] + ), ], ) @@ -69,8 +79,19 @@ def connected_scatter_factory(group: str): avoid misinterpretation. """ ), - vm.Graph(figure=px.line(gapminder.query("country == 'Australia'"), x="year", y="lifeExp", markers=True)), - make_code_clipboard_from_py_file("connected_scatter.py"), + vm.Graph(figure=connected_scatter.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("connected_scatter.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("connected_scatter.py", mode="plotly")], + ), + ] + ), ], ) @@ -99,15 +120,19 @@ def column_and_line_factory(group: str): for other types of data comparisons. """ ), - vm.Graph( - figure=column_and_line( - gapminder.query("country == 'Vietnam'"), - y_column="gdpPercap", - y_line="lifeExp", - x="year", - ) + vm.Graph(figure=column_and_line.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("column_and_line.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("column_and_line.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("column_and_line.py"), ], ) @@ -139,14 +164,18 @@ def waterfall_factory(group: str): colors for positive and negative values, and arrange categories logically to tell a coherent story. """ ), - vm.Graph( - figure=waterfall( - waterfall_data, - x="x", - y="y", - measure="measure", - ) + vm.Graph(figure=waterfall.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("waterfall.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("waterfall.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("waterfall.py"), ], ) diff --git a/pages/_pages_utils.py b/pages/_pages_utils.py index 3227cb05c926bc66b938a4bb8db1bcc806909e45..6b1db5dc26fc777d4f93dd590ba0c30daf94b834 100644 --- a/pages/_pages_utils.py +++ b/pages/_pages_utils.py @@ -3,105 +3,57 @@ import logging from pathlib import Path +import autoflake import black -import pandas as pd -import vizro.plotly.express as px +import isort from custom_components import CodeClipboard # To disable logging info messages caused by black.format_str: https://github.com/psf/black/issues/2058 logging.getLogger("blib2to3").setLevel(logging.ERROR) +VIZRO_CODE_TEMPLATE = """ +import vizro.models as vm +from vizro import Vizro +{example_code} +page = vm.Page(title="My page", components=[vm.Graph(figure=fig)]) +dashboard = vm.Dashboard(pages=[page]) +Vizro().build(dashboard).run() +""" + + +def _format_and_lint(code_string: str, line_length: int) -> str: + """Inspired by vizro.models._base._format_and_lint. The only difference is that this does isort too.""" + # Tracking https://github.com/astral-sh/ruff/issues/659 for proper Python API + # Good example: https://github.com/astral-sh/ruff/issues/8401#issuecomment-1788806462 + # While we wait for the API, we can use autoflake and black to process code strings + # Isort is needed since otherwise example code looks quite strange sometimes. Autoflake is needed since isort can't + # remove imports by itself: https://github.com/PyCQA/isort/issues/1105. + + removed_imports = autoflake.fix_code(code_string, remove_all_unused_imports=True) + sorted_imports = isort.code(removed_imports) + # Black doesn't yet have a Python API, so format_str might not work at some point in the future. + # https://black.readthedocs.io/en/stable/faq.html#does-black-have-an-api + formatted = black.format_str(sorted_imports, mode=black.Mode(line_length=line_length)) + return formatted + -def make_code_clipboard_from_py_file(filepath: str): +def make_code_clipboard_from_py_file(filepath: str, mode="vizro"): # Black doesn't yet have a Python API, so format_str might not work at some point in the future. # https://black.readthedocs.io/en/stable/faq.html#does-black-have-an-api - filepath = Path(__file__).parents[1] / "pages/examples" / filepath + example_code = (Path(__file__).parents[1] / "pages/examples" / filepath).read_text() + + if mode == "vizro": + example_code = VIZRO_CODE_TEMPLATE.format(example_code=example_code) + else: + replacements = {"import vizro.plotly.express as px": "import plotly.express as px", '@capture("graph")': ""} + for old_code, new_code in replacements.items(): + example_code = example_code.replace(old_code, new_code) + return CodeClipboard( - code=black.format_str(filepath.read_text(encoding="utf-8"), mode=black.Mode(line_length=80)), + code=_format_and_lint(example_code, line_length=80), + mode=mode, language="python", ) PAGE_GRID = [[0, 0, 0, 0, 0, 0, 0]] * 2 + [[1, 1, 1, 1, 2, 2, 2]] * 5 - -# DATA -------------------------------------------------------------- -gapminder = px.data.gapminder() -iris = px.data.iris() -stocks = px.data.stocks() -tips = px.data.tips() -wind = px.data.wind() - -ages = pd.DataFrame( - { - "Age": ["0-19", "20-29", "30-39", "40-49", "50-59", ">=60"], - "Male": [800, 2000, 4200, 5000, 2100, 800], - "Female": [1000, 3000, 3500, 3800, 3600, 700], - } -) -sankey_data = pd.DataFrame( - { - "Origin": [0, 1, 0, 2, 3, 3], - "Destination": [2, 3, 3, 4, 4, 5], - "Value": [8, 4, 2, 8, 4, 2], - } -) - -funnel_data = pd.DataFrame( - {"Stage": ["Leads", "Sales calls", "Follow-up", "Conversion", "Sales"], "Value": [10, 7, 4, 2, 1]} -) - -stepped_line_data = pd.DataFrame( - { - "year": [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003], - "rate": [0.10, 0.12, 0.15, 0.13, 0.14, 0.13, 0.14, 0.16, 0.15], - } -) - - -carshare = px.data.carshare() - -tasks = pd.DataFrame( - [ - {"Task": "Job A", "Start": "2009-01-01", "Finish": "2009-02-28"}, - {"Task": "Job B", "Start": "2009-03-05", "Finish": "2009-04-15"}, - {"Task": "Job C", "Start": "2009-02-20", "Finish": "2009-05-30"}, - ] -) - -waterfall_data = pd.DataFrame( - { - "x": ["Sales", "Consulting", "Net revenue", "Purchases", "Other expenses", "Profit before tax"], - "y": [60, 80, 0, -40, -20, 0], - "measure": ["relative", "relative", "total", "relative", "relative", "total"], - } -) - - -pastries = pd.DataFrame( - { - "pastry": [ - "Scones", - "Bagels", - "Muffins", - "Cakes", - "Donuts", - "Cookies", - "Croissants", - "Eclairs", - "Brownies", - "Tarts", - "Macarons", - "Pies", - ], - "Profit Ratio": [-0.10, -0.15, -0.05, 0.10, 0.05, 0.20, 0.15, -0.08, 0.08, -0.12, 0.02, -0.07], - } -) - - -salaries = pd.DataFrame( - { - "Job": ["Developer", "Analyst", "Manager", "Specialist"] * 2, - "Salary": [60000, 55000, 70000, 50000, 130000, 110000, 96400, 80000], - "Range": ["Min"] * 4 + ["Max"] * 4, - } -) diff --git a/pages/correlation.py b/pages/correlation.py index 199042261b69f346cf40da233c4186336d43e5c0..8797ecbaf6d986deb85eb8d675332095ded35d86 100644 --- a/pages/correlation.py +++ b/pages/correlation.py @@ -1,12 +1,12 @@ """Correlation charts.""" import vizro.models as vm -import vizro.plotly.express as px from pages._factories import column_and_line_factory, connected_scatter_factory -from pages._pages_utils import PAGE_GRID, gapminder, iris, make_code_clipboard_from_py_file +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import bubble, scatter, scatter_matrix -scatter = vm.Page( +scatter_page = vm.Page( title="Scatter", path="correlation/scatter", layout=vm.Layout(grid=PAGE_GRID), @@ -29,14 +29,24 @@ scatter = vm.Page( that correlation is not causation. Make sure your audience does not draw the wrong conclusions. """ ), - vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species")), - make_code_clipboard_from_py_file("scatter.py"), + vm.Graph(figure=scatter.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("scatter.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("scatter.py", mode="plotly")], + ), + ] + ), ], ) -connected_scatter = connected_scatter_factory("correlation") +connected_scatter_page = connected_scatter_factory("correlation") -scatter_matrix = vm.Page( +scatter_matrix_page = vm.Page( title="Scatter matrix", path="correlation/scatter-matrix", layout=vm.Layout(grid=PAGE_GRID), @@ -60,14 +70,23 @@ scatter_matrix = vm.Page( ensure clarity and readability of the chart. """ ), - vm.Graph( - figure=px.scatter_matrix(iris, dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"]) + vm.Graph(figure=scatter_matrix.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("scatter_matrix.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("scatter_matrix.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("scatter_matrix.py"), ], ) -bubble = vm.Page( +bubble_page = vm.Page( title="Bubble", path="correlation/bubble", layout=vm.Layout(grid=PAGE_GRID), @@ -91,10 +110,21 @@ bubble = vm.Page( providing deeper insights than a standard scatter plot. """ ), - vm.Graph(figure=px.scatter(gapminder.query("year==2007"), x="gdpPercap", y="lifeExp", size="pop", size_max=60)), - make_code_clipboard_from_py_file("bubble.py"), + vm.Graph(figure=bubble.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("bubble.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("bubble.py", mode="plotly")], + ), + ] + ), ], ) -column_and_line = column_and_line_factory("correlation") -pages = [scatter, connected_scatter, scatter_matrix, bubble, column_and_line] +column_and_line_page = column_and_line_factory("correlation") + +pages = [scatter_page, connected_scatter_page, scatter_matrix_page, bubble_page, column_and_line_page] diff --git a/pages/deviation.py b/pages/deviation.py index 406c8d699a929d7ca37fe414b03354f4cff75d02..b3c0abb3319db215871ae6742e513300b75bdd54 100644 --- a/pages/deviation.py +++ b/pages/deviation.py @@ -1,16 +1,15 @@ """Deviation charts.""" -import plotly.io as pio import vizro.models as vm -import vizro.plotly.express as px from pages._factories import butterfly_factory -from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file, pastries +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import diverging_bar, diverging_stacked_bar -butterfly = butterfly_factory("deviation") +butterfly_page = butterfly_factory("deviation") -diverging_bar = vm.Page( +diverging_bar_page = vm.Page( title="Diverging bar", path="deviation/diverging-bar", layout=vm.Layout(grid=PAGE_GRID), @@ -36,19 +35,63 @@ diverging_bar = vm.Page( of values. Ensure a consistent scale on both sides of the baseline to avoid misleading interpretations. """ ), - vm.Graph( - figure=px.bar( - pastries.sort_values("Profit Ratio"), - orientation="h", - x="Profit Ratio", - y="pastry", - color="Profit Ratio", - color_continuous_scale=pio.templates["vizro_dark"].layout.colorscale.diverging, - color_continuous_midpoint=0, - ), + vm.Graph(figure=diverging_bar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("diverging_bar.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("diverging_bar.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("diverging_bar.py"), ], ) -pages = [butterfly, diverging_bar] +diverging_stacked_bar_page = vm.Page( + title="Diverging stacked bar", + path="deviation/diverging-stacked-bar", + layout=vm.Layout(grid=PAGE_GRID), + components=[ + vm.Card( + text=""" + + #### What is a diverging stacked bar? + + A diverging stacked bar chart is like a stacked bar chart but aligns bars on a central baseline instead of + the left or right. It displays positive and negative values, with each bar divided into segments for + different categories. This type of chart is commonly used for percentage shares, especially in survey + results using Likert scales (e.g., Strongly Disagree, Disagree, Agree, Strongly Agree). + +   + + #### When should I use it? + + A diverging stacked bar chart is useful for comparing positive and negative values and showing the + composition of each bar. However, use this chart with caution: since none of the segments share a + common baseline, direct comparisons can be more challenging. For clearer comparisons, consider using a + 100% stacked bar chart with a baseline starting from the left or right. For more insights on the potential + pitfalls, we recommend reading the article from + [Datawrapper on diverging stacked bar charts](https://blog.datawrapper.de/divergingbars/). + """ + ), + vm.Graph(figure=diverging_stacked_bar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("diverging_stacked_bar.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("diverging_stacked_bar.py", mode="plotly")], + ), + ] + ), + ], +) + +pages = [butterfly_page, diverging_bar_page, diverging_stacked_bar_page] diff --git a/pages/distribution.py b/pages/distribution.py index b6888bb95316e7b2199eaae7f9a2af9ee49f5bd7..0e941cb8e59a5be297257a236a00ba4346f46e7b 100644 --- a/pages/distribution.py +++ b/pages/distribution.py @@ -1,13 +1,12 @@ """Distribution charts.""" import vizro.models as vm -import vizro.plotly.express as px -from custom_charts import dumbbell from pages._factories import butterfly_factory -from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file, salaries, tips +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import boxplot, dumbbell, histogram, violin -violin = vm.Page( +violin_page = vm.Page( title="Violin", path="distribution/violin", layout=vm.Layout(grid=PAGE_GRID), @@ -28,20 +27,22 @@ violin = vm.Page( inter-quartile range, the confidence intervals and the median. """ ), - vm.Graph( - figure=px.violin( - tips, - y="total_bill", - x="day", - color="day", - box=True, - ) + vm.Graph(figure=violin.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("violin.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("violin.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("violin.py"), ], ) -boxplot = vm.Page( +boxplot_page = vm.Page( title="Boxplot", path="distribution/boxplot", layout=vm.Layout(grid=PAGE_GRID), @@ -66,21 +67,24 @@ boxplot = vm.Page( the whiskers. """ ), - vm.Graph( - figure=px.box( - tips, - y="total_bill", - x="day", - color="day", - ) + vm.Graph(figure=boxplot.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("boxplot.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("boxplot.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("boxplot.py"), ], ) -butterfly = butterfly_factory("distribution") +butterfly_page = butterfly_factory("distribution") -histogram = vm.Page( +histogram_page = vm.Page( title="Histogram", path="distribution/histogram", layout=vm.Layout(grid=PAGE_GRID), @@ -102,12 +106,22 @@ histogram = vm.Page( immediately clear. """ ), - vm.Graph(figure=px.histogram(tips, x="total_bill")), - make_code_clipboard_from_py_file("histogram.py"), + vm.Graph(figure=histogram.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("histogram.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("histogram.py", mode="plotly")], + ), + ] + ), ], ) -dumbbell = vm.Page( +dumbbell_page = vm.Page( title="Dumbbell", path="distribution/dumbbell", layout=vm.Layout(grid=PAGE_GRID), @@ -129,10 +143,20 @@ dumbbell = vm.Page( of changes or to distinguish between categories. """ ), - vm.Graph(figure=dumbbell(salaries, y="Job", x="Salary", color="Range")), - make_code_clipboard_from_py_file("dumbbell.py"), + vm.Graph(figure=dumbbell.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("dumbbell.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("dumbbell.py", mode="plotly")], + ), + ] + ), ], ) -pages = [violin, boxplot, butterfly, dumbbell, histogram] +pages = [violin_page, boxplot_page, butterfly_page, dumbbell_page, histogram_page] diff --git a/pages/examples/area.py b/pages/examples/area.py index 50d0d3ae27ffce1ca1946d655476c7e83414b421..351b2d5048aaab08a9498bc37f62e96becbe78dc 100644 --- a/pages/examples/area.py +++ b/pages/examples/area.py @@ -1,13 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro stocks = px.data.stocks() -page = vm.Page( - title="Area", - components=[vm.Graph(figure=px.area(stocks, x="date", y="GOOG"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.area(stocks, x="date", y="GOOG") diff --git a/pages/examples/bar.py b/pages/examples/bar.py index 6afdd3040341e4f441255a958700483334bb140c..9d20c7bcd2796a26d94afb19de7819083f97639d 100644 --- a/pages/examples/bar.py +++ b/pages/examples/bar.py @@ -1,24 +1,7 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() - -page = vm.Page( - title="Bar", - components=[ - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" - ), - x="pop", - y="country", - orientation="h", - ) - ) - ], +gapminder = px.data.gapminder().query( + "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.bar(gapminder, x="pop", y="country", orientation="h") diff --git a/pages/examples/boxplot.py b/pages/examples/boxplot.py index ce9c79e836824c35e47f1df11c225f2683d1b89c..2feaa608670e76e53447078b2527a0b7a6ff7a78 100644 --- a/pages/examples/boxplot.py +++ b/pages/examples/boxplot.py @@ -1,15 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() -page = vm.Page( - title="Boxplot", - components=[ - vm.Graph(figure=px.boxplot(tips, y="total_bill", x="day", color="day")), - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.box(tips, y="total_bill", x="day", color="day") diff --git a/pages/examples/bubble.py b/pages/examples/bubble.py index 6da0aa8166486b037c304cbef70eba2607000149..b769b82da04195b65264125b2d72c63d723ba719 100644 --- a/pages/examples/bubble.py +++ b/pages/examples/bubble.py @@ -1,15 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() +gapminder = px.data.gapminder().query("year==2007") -page = vm.Page( - title="Bubble", - components=[ - vm.Graph(figure=px.scatter(gapminder.query("year==2007"), x="gdpPercap", y="lifeExp", size="pop", size_max=60)) - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.scatter(gapminder, x="gdpPercap", y="lifeExp", size="pop", size_max=60) diff --git a/pages/examples/bubble_map.py b/pages/examples/bubble_map.py index 1ae527845700550a19fc67217f1bba74920a7bb2..0d23e74433882b89a36a44059d3025ec03908f80 100644 --- a/pages/examples/bubble_map.py +++ b/pages/examples/bubble_map.py @@ -1,25 +1,7 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro carshare = px.data.carshare() -page = vm.Page( - title="Bubble map", - components=[ - vm.Graph( - figure=px.scatter_map( - carshare, - lat="centroid_lat", - lon="centroid_lon", - size="car_hours", - size_max=15, - opacity=0.5, - zoom=10, - ) - ) - ], +fig = px.scatter_map( + carshare, lat="centroid_lat", lon="centroid_lon", size="car_hours", size_max=15, opacity=0.5, zoom=10 ) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() diff --git a/pages/examples/butterfly.py b/pages/examples/butterfly.py index 69c66ed8db82c96d0452d57bf7f2027988fe9912..52a7ed544440e902a170ad42be3516b9d121510f 100644 --- a/pages/examples/butterfly.py +++ b/pages/examples/butterfly.py @@ -1,9 +1,30 @@ import pandas as pd +import plotly.express as px import plotly.graph_objects as go -import vizro.models as vm -from vizro import Vizro from vizro.models.types import capture + +@capture("graph") +def butterfly(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + fig = px.bar(data_frame, **kwargs) + + orientation = fig.data[0].orientation + x_or_y = "x" if orientation == "h" else "y" + + fig.update_traces({f"{x_or_y}axis": f"{x_or_y}2"}, selector=1) + fig.update_layout({f"{x_or_y}axis2": fig.layout[f"{x_or_y}axis"]}) + fig.update_layout( + {f"{x_or_y}axis": {"autorange": "reversed", "domain": [0, 0.5]}, f"{x_or_y}axis2": {"domain": [0.5, 1]}} + ) + + if orientation == "h": + fig.add_vline(x=0, line_width=2, line_color="grey") + else: + fig.add_hline(y=0, line_width=2, line_color="grey") + + return fig + + ages = pd.DataFrame( { "Age": ["0-19", "20-29", "30-39", "40-49", "50-59", ">=60"], @@ -12,36 +33,4 @@ ages = pd.DataFrame( } ) - -@capture("graph") -def butterfly(data_frame: pd.DataFrame, x1: str, x2: str, y: str): - fig = go.Figure() - fig.add_trace( - go.Bar( - x=-data_frame[x1], - y=data_frame[y], - orientation="h", - name=x1, - ) - ) - fig.add_trace( - go.Bar( - x=data_frame[x2], - y=data_frame[y], - orientation="h", - name=x2, - ) - ) - fig.update_layout(barmode="relative") - return fig - - -dashboard = vm.Dashboard( - pages=[ - vm.Page( - title="Butterfly", - components=[vm.Graph(figure=butterfly(ages, x1="Male", x2="Female", y="Age"))], - ) - ] -) -Vizro().build(dashboard).run() +fig = butterfly(ages, x=["Male", "Female"], y="Age", labels={"value": "Population", "variable": "Sex"}) diff --git a/pages/examples/choropleth.py b/pages/examples/choropleth.py index 95c5cac5f7104e62fe0968db549d770f3ac28923..88ff1d09600d7357272bcf985588d69cd3f68803 100644 --- a/pages/examples/choropleth.py +++ b/pages/examples/choropleth.py @@ -1,19 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() +gapminder = px.data.gapminder().query("year == 2007") -page = vm.Page( - title="Choropleth", - components=[ - vm.Graph( - figure=px.choropleth( - gapminder.query("year == 2007"), locations="iso_alpha", color="lifeExp", hover_name="country" - ) - ) - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.choropleth(gapminder, locations="iso_alpha", color="lifeExp", hover_name="country") diff --git a/pages/examples/column_and_line.py b/pages/examples/column_and_line.py index 85a5fb11688f7303dafaadbd546348d8ca38de75..abb6b4e2ccf6bbed5836a84136bcfa498d7fc44d 100644 --- a/pages/examples/column_and_line.py +++ b/pages/examples/column_and_line.py @@ -1,53 +1,38 @@ +from typing import Union + import pandas as pd import plotly.graph_objects as go -import vizro.models as vm import vizro.plotly.express as px from plotly.subplots import make_subplots -from vizro import Vizro from vizro.models.types import capture -gapminder = px.data.gapminder() - @capture("graph") -def column_and_line(data_frame: pd.DataFrame, x: str, y_column: str, y_line: str) -> go.Figure: - """Creates a combined column and line chart using Plotly.""" - fig = make_subplots(specs=[[{"secondary_y": True}]]) - - fig.add_trace( - go.Bar(x=data_frame[x], y=data_frame[y_column], name=y_column), - secondary_y=False, +def column_and_line( + data_frame: pd.DataFrame, + x: Union[str, pd.Series, list[str], list[pd.Series]], + y_column: Union[str, pd.Series, list[str], list[pd.Series]], + y_line: Union[str, pd.Series, list[str], list[pd.Series]], +) -> go.Figure: + bar = px.bar(data_frame, x=x, y=y_column) + fig = make_subplots(figure=bar, specs=[[{"secondary_y": True}]]) + + line = px.line( + data_frame, + x=x, + y=y_line, + markers=True, + color_discrete_sequence=fig.layout.template.layout.colorway[len(bar.data) :], ) - fig.add_trace( - go.Scatter(x=data_frame[x], y=data_frame[y_line], name=y_line), - secondary_y=True, - ) + for trace in line.data: + fig.add_trace(trace, secondary_y=True) - fig.update_layout( - xaxis={"type": "category", "title": x}, - yaxis={"tickmode": "sync", "title": y_column}, - yaxis2={"tickmode": "sync", "overlaying": "y", "title": y_line}, - ) + fig.update_layout(yaxis2={"tickmode": "sync", "overlaying": "y", "title": line.layout.yaxis.title}) return fig -dashboard = vm.Dashboard( - pages=[ - vm.Page( - title="Column and line", - components=[ - vm.Graph( - figure=column_and_line( - gapminder.query("country == 'Vietnam'"), - y_column="gdpPercap", - y_line="lifeExp", - x="year", - ) - ) - ], - ) - ] -) -Vizro().build(dashboard).run() +gapminder = px.data.gapminder().query("country == 'Vietnam'") + +fig = column_and_line(gapminder, y_column="gdpPercap", y_line="lifeExp", x="year") diff --git a/pages/examples/connected_scatter.py b/pages/examples/connected_scatter.py index 68da341c940f1c9d988364279b5d8d44a1870353..ae23357eca814a10cb48030cc00ac823e86e12a8 100644 --- a/pages/examples/connected_scatter.py +++ b/pages/examples/connected_scatter.py @@ -1,15 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() +gapminder = px.data.gapminder().query("country == 'Australia'") -page = vm.Page( - title="Connected scatter", - components=[ - vm.Graph(figure=px.line(gapminder.query("country == 'Australia'"), x="year", y="lifeExp", markers=True)) - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.line(gapminder, x="year", y="lifeExp", markers=True) diff --git a/pages/examples/diverging_bar.py b/pages/examples/diverging_bar.py index ae839d4537087128124cc765ded59ded0c61377a..e80006e044e27699a40d6f61528759bcefef280f 100644 --- a/pages/examples/diverging_bar.py +++ b/pages/examples/diverging_bar.py @@ -1,8 +1,5 @@ import pandas as pd -import plotly.io as pio -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro pastries = pd.DataFrame( { @@ -15,31 +12,9 @@ pastries = pd.DataFrame( "Cookies", "Croissants", "Eclairs", - "Brownies", - "Tarts", - "Macarons", - "Pies", ], - "Profit Ratio": [-0.10, -0.15, -0.05, 0.10, 0.05, 0.20, 0.15, -0.08, 0.08, -0.12, 0.02, -0.07], + "Profit Ratio": [-0.10, -0.05, 0.10, 0.05, 0.15, -0.08, 0.08, -0.12], } -) +).sort_values("Profit Ratio") -page = vm.Page( - title="Diverging bar", - components=[ - vm.Graph( - figure=px.bar( - pastries.sort_values("Profit Ratio"), - orientation="h", - x="Profit Ratio", - y="pastry", - color="Profit Ratio", - color_continuous_scale=pio.templates["vizro_dark"].layout.colorscale.diverging, - color_continuous_midpoint=0, - ), - ), - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.bar(pastries, x="Profit Ratio", y="pastry") diff --git a/pages/examples/diverging_stacked_bar.py b/pages/examples/diverging_stacked_bar.py new file mode 100644 index 0000000000000000000000000000000000000000..ae08c662989391ebdecc9b24475ee37174918032 --- /dev/null +++ b/pages/examples/diverging_stacked_bar.py @@ -0,0 +1,68 @@ +import pandas as pd +import plotly.express as px +import plotly.graph_objects as go +from vizro.models.types import capture + + +@capture("graph") +def diverging_stacked_bar(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + fig = px.bar(data_frame, **kwargs) + + for i, trace in enumerate(fig.data): + trace.update(legendrank=i) + + if "color_discrete_sequence" not in kwargs and "color_discrete_map" not in kwargs: + colorscale = [list(x) for x in fig.layout.template.layout.colorscale.diverging] + colors = px.colors.sample_colorscale(colorscale, len(fig.data), 0.2, 0.8) + for trace, color in zip(fig.data, colors): + trace.update(marker_color=color) + + mutable_traces = list(fig.data) + mutable_traces[: len(fig.data) // 2] = reversed(fig.data[: len(fig.data) // 2]) + fig.data = mutable_traces + + orientation = fig.data[0].orientation + x_or_y = "x" if orientation == "h" else "y" + + for trace_idx in range(len(fig.data) // 2): + fig.update_traces({f"{x_or_y}axis": f"{x_or_y}2"}, selector=trace_idx) + + fig.update_layout({f"{x_or_y}axis2": fig.layout[f"{x_or_y}axis"]}) + fig.update_layout( + {f"{x_or_y}axis": {"autorange": "reversed", "domain": [0, 0.5]}, f"{x_or_y}axis2": {"domain": [0.5, 1]}} + ) + + if orientation == "h": + fig.add_vline(x=0, line_width=2, line_color="grey") + else: + fig.add_hline(y=0, line_width=2, line_color="grey") + + return fig + + +pastries = pd.DataFrame( + { + "pastry": [ + "Scones", + "Bagels", + "Muffins", + "Cakes", + "Donuts", + "Cookies", + "Croissants", + "Eclairs", + ], + "Strongly Disagree": [20, 30, 10, 5, 15, 5, 10, 25], + "Disagree": [30, 25, 20, 10, 20, 10, 15, 30], + "Agree": [30, 25, 40, 40, 45, 40, 40, 25], + "Strongly Agree": [20, 20, 30, 45, 20, 45, 35, 20], + } +) + +fig = diverging_stacked_bar( + data_frame=pastries, + x=["Strongly Disagree", "Disagree", "Agree", "Strongly Agree"], + y="pastry", + labels={"value": "Response count", "variable": "Opinion"}, + title="I would recommend this pastry to my friends", +) diff --git a/pages/examples/donut.py b/pages/examples/donut.py index 3005c2fdcd8332d50e8625c125c6650ecf42c41b..105a0be39b9d2b041c0caf6a8c6e4cc4a7daf086 100644 --- a/pages/examples/donut.py +++ b/pages/examples/donut.py @@ -1,13 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() -page = vm.Page( - title="Donut", - components=[vm.Graph(figure=px.pie(tips, values="tip", names="day", hole=0.4))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.pie(tips, values="tip", names="day", hole=0.4) diff --git a/pages/examples/dot_map.py b/pages/examples/dot_map.py index 91d51b6228beecfd77527e6c14c8dbbfe7aecdf9..9b40b22999a0746aa13ed5bd4a50f02c9a558c6e 100644 --- a/pages/examples/dot_map.py +++ b/pages/examples/dot_map.py @@ -1,23 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro carshare = px.data.carshare() -page = vm.Page( - title="Dot map", - components=[ - vm.Graph( - figure=px.scatter_map( - carshare, - lat="centroid_lat", - lon="centroid_lon", - opacity=0.5, - zoom=10, - ) - ) - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.scatter_map(carshare, lat="centroid_lat", lon="centroid_lon", opacity=0.5, zoom=10) diff --git a/pages/examples/dumbbell.py b/pages/examples/dumbbell.py index 43802dfd42e63870c44bbd581333b73007a48754..1f66551f0d5a9e3eee3bd96039d7802a4a3f5b81 100644 --- a/pages/examples/dumbbell.py +++ b/pages/examples/dumbbell.py @@ -1,46 +1,41 @@ import pandas as pd -import vizro.models as vm +import plotly.graph_objects as go import vizro.plotly.express as px -from plotly import graph_objects as go -from vizro import Vizro from vizro.models.types import capture -salaries = pd.DataFrame( - { - "Job": ["Developer", "Analyst", "Manager", "Specialist"] * 2, - "Salary": [60000, 55000, 70000, 50000, 130000, 110000, 96400, 80000], - "Range": ["Min"] * 4 + ["Max"] * 4, - } -) - @capture("graph") -def dumbbell(data_frame: pd.DataFrame, x: str, y: str, color: str) -> go.Figure: - # Add two dots to plot - fig = px.scatter(data_frame, y=y, x=x, color=color) - - # Add lines between dots - for y_value, group in data_frame.groupby(y): +def dumbbell(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + fig = px.scatter(data_frame, **kwargs) + + orientation = fig.data[0].orientation + x_or_y = "x" if orientation == "h" else "y" + y_or_x = "y" if orientation == "h" else "x" + + for x_or_y_0, x_or_y_1, y_or_x_0, y_or_x_1 in zip( + fig.data[0][x_or_y], + fig.data[1][x_or_y], + fig.data[0][y_or_x], + fig.data[1][y_or_x], + ): fig.add_shape( + **{f"{x_or_y}0": x_or_y_0, f"{x_or_y}1": x_or_y_1, f"{y_or_x}0": y_or_x_0, f"{y_or_x}1": y_or_x_1}, type="line", layer="below", - y0=y_value, - y1=y_value, - x0=group[x].min(), - x1=group[x].max(), line_color="grey", line_width=3, ) - # Increase size of dots fig.update_traces(marker_size=12) return fig -page = vm.Page( - title="Dumbbell", - components=[vm.Graph(figure=dumbbell(salaries, y="Job", x="Salary", color="Range"))], +salaries = pd.DataFrame( + { + "Job": ["Developer", "Analyst", "Manager", "Specialist"], + "Min": [60000, 55000, 70000, 50000], + "Max": [130000, 110000, 96400, 80000], + } ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = dumbbell(salaries, y="Job", x=["Min", "Max"], labels={"variable": "", "value": "Salary in $"}) diff --git a/pages/examples/funnel.py b/pages/examples/funnel.py index 221430cbf654f51e848437a4239da61058e0bf72..2e26bd71c96c43908df31542ac62d26b8883bae1 100644 --- a/pages/examples/funnel.py +++ b/pages/examples/funnel.py @@ -1,16 +1,8 @@ import pandas as pd -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro funnel_data = pd.DataFrame( {"Stage": ["Leads", "Sales calls", "Follow-up", "Conversion", "Sales"], "Value": [10, 7, 4, 2, 1]} ) -page = vm.Page( - title="Funnel", - components=[vm.Graph(figure=px.funnel_area(funnel_data, names="Stage", values="Value"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.funnel_area(funnel_data, names="Stage", values="Value") diff --git a/pages/examples/gantt.py b/pages/examples/gantt.py index 951ca9e2e4e24d166aadf841f573be041dcaa1fa..4627759c3df34b0b25a8e7e4a06bd54d70819a88 100644 --- a/pages/examples/gantt.py +++ b/pages/examples/gantt.py @@ -1,7 +1,5 @@ import pandas as pd -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tasks = pd.DataFrame( [ @@ -9,15 +7,6 @@ tasks = pd.DataFrame( {"Task": "Job B", "Start": "2009-03-05", "Finish": "2009-04-15"}, {"Task": "Job C", "Start": "2009-02-20", "Finish": "2009-05-30"}, ] -) +).sort_values("Start", ascending=False) - -page = vm.Page( - title="Gantt", - components=[ - vm.Graph(px.timeline(tasks.sort_values("Start", ascending=False), x_start="Start", x_end="Finish", y="Task")) - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.timeline(tasks, x_start="Start", x_end="Finish", y="Task") diff --git a/pages/examples/heatmap.py b/pages/examples/heatmap.py index 350e9e8234ab7c790bf63c1c8aaecb5caa8110b8..ace051c7b37a5940385915682b896708c75fc5e5 100644 --- a/pages/examples/heatmap.py +++ b/pages/examples/heatmap.py @@ -1,15 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() -page = vm.Page( - title="Heatmap", - components=[ - vm.Graph(figure=px.density_heatmap(tips, x="day", y="size", z="tip", histfunc="avg", text_auto="$.2f")), - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.density_heatmap(tips, x="day", y="size", z="tip", histfunc="avg", text_auto="$.2f") diff --git a/pages/examples/histogram.py b/pages/examples/histogram.py index dc5b3856d2db70b2b887dd200fa2c696a7769e6b..2f667f1a47b2663acee2314453acfde857a5d080 100644 --- a/pages/examples/histogram.py +++ b/pages/examples/histogram.py @@ -1,13 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() -page = vm.Page( - title="Histogram", - components=[vm.Graph(px.histogram(tips, x="total_bill"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.histogram(tips, x="total_bill") diff --git a/pages/examples/line.py b/pages/examples/line.py index c442a89949f229fe3383f0ce41bbf11a2198e441..d9eacbf9055e0f10328c4945e80d6af1196f36bc 100644 --- a/pages/examples/line.py +++ b/pages/examples/line.py @@ -1,13 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro stocks = px.data.stocks() -page = vm.Page( - title="Line", - components=[vm.Graph(figure=px.line(stocks, x="date", y="GOOG"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.line(stocks, x="date", y="GOOG") diff --git a/pages/examples/magnitude_column.py b/pages/examples/magnitude_column.py index 04635ca85ac5d491db67586d96bb6a5c6dbbccf6..1230b613748ba3e599195ed070c5fe152d3866ff 100644 --- a/pages/examples/magnitude_column.py +++ b/pages/examples/magnitude_column.py @@ -1,23 +1,7 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() - -page = vm.Page( - title="Column", - components=[ - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" - ), - y="pop", - x="country", - ) - ) - ], +gapminder = px.data.gapminder().query( + "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.bar(gapminder, y="pop", x="country") diff --git a/pages/examples/ordered_bar.py b/pages/examples/ordered_bar.py index 316b0b031a838e2cfc36a6b936dea9ace50763f5..63282a1a789fb358699b9d596b1e1010b4438287 100644 --- a/pages/examples/ordered_bar.py +++ b/pages/examples/ordered_bar.py @@ -1,25 +1,9 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() - - -page = vm.Page( - title="Ordered bar", - components=[ - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" - ).sort_values("pop"), - x="pop", - y="country", - orientation="h", - ) - ) - ], +gapminder = ( + px.data.gapminder() + .query("year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])") + .sort_values("pop") ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.bar(gapminder, x="pop", y="country", orientation="h") diff --git a/pages/examples/ordered_column.py b/pages/examples/ordered_column.py index 07bb37fe77c3b5b72c520e02fc9025fc3e485a6d..e16f6532491f2eb10abf9a25b50920e61d2d8b98 100644 --- a/pages/examples/ordered_column.py +++ b/pages/examples/ordered_column.py @@ -1,24 +1,9 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() - - -page = vm.Page( - title="Ordered column", - components=[ - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" - ).sort_values("pop"), - y="pop", - x="country", - ) - ) - ], +gapminder = ( + px.data.gapminder() + .query("year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])") + .sort_values("pop") ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.bar(gapminder, y="pop", x="country") diff --git a/pages/examples/paired_bar.py b/pages/examples/paired_bar.py index 0d15e480c0156f981aa4a906a9bb5b124a9e4720..d7090de30e1d953db86936c19cf50510ddb1f670 100644 --- a/pages/examples/paired_bar.py +++ b/pages/examples/paired_bar.py @@ -1,26 +1,13 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() - -page = vm.Page( - title="Paired bar", - components=[ - vm.Graph( - figure=px.histogram( - tips, - y="day", - x="total_bill", - color="sex", - barmode="group", - orientation="h", - category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]}, - ), - ) - ], +fig = px.histogram( + tips, + y="day", + x="total_bill", + color="sex", + barmode="group", + orientation="h", + category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]}, ) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() diff --git a/pages/examples/paired_column.py b/pages/examples/paired_column.py index b6292c14c20878b070ba848ab743312cd7899e7b..df7ac1549846aca0283d30c370878942b89ce86f 100644 --- a/pages/examples/paired_column.py +++ b/pages/examples/paired_column.py @@ -1,25 +1,7 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() - -page = vm.Page( - title="Paired column", - components=[ - vm.Graph( - figure=px.histogram( - tips, - x="day", - y="total_bill", - color="sex", - barmode="group", - category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]}, - ), - ) - ], +fig = px.histogram( + tips, x="day", y="total_bill", color="sex", barmode="group", category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]} ) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() diff --git a/pages/examples/parallel_coordinates.py b/pages/examples/parallel_coordinates.py index c372ec9a775e08c5ed4b17bb79f3b0bccf0373ba..3dbb697f8a1a9718e55aa0f7cc8901b42c7ee8d6 100644 --- a/pages/examples/parallel_coordinates.py +++ b/pages/examples/parallel_coordinates.py @@ -1,19 +1,7 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro iris = px.data.iris() -page = vm.Page( - title="Parallel coordinates", - components=[ - vm.Graph( - figure=px.parallel_coordinates( - iris, color="species_id", dimensions=["sepal_width", "sepal_length", "petal_width", "petal_length"] - ) - ) - ], +fig = px.parallel_coordinates( + iris, color="species_id", dimensions=["sepal_width", "sepal_length", "petal_width", "petal_length"] ) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() diff --git a/pages/examples/pie.py b/pages/examples/pie.py index 596abb2ff2dc87fb167c0d848bf7888ee9c86897..88ad1df09d9a3880a3aa0ca82ecbe915e0040592 100644 --- a/pages/examples/pie.py +++ b/pages/examples/pie.py @@ -1,13 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() -page = vm.Page( - title="Pie", - components=[vm.Graph(figure=px.pie(tips, values="tip", names="day"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.pie(tips, values="tip", names="day") diff --git a/pages/examples/radar.py b/pages/examples/radar.py index 1ff7de8656616e8761dce53c113c529f9f3d1885..1792722170112e93a093edab49c22c68905d88d6 100644 --- a/pages/examples/radar.py +++ b/pages/examples/radar.py @@ -1,25 +1,15 @@ -import vizro.models as vm +import pandas as pd import vizro.plotly.express as px -from vizro import Vizro from vizro.models.types import capture -wind = px.data.wind() - @capture("graph") -def radar(data_frame, **kwargs): - """Creates a radar chart using Plotly's line_polar.""" +def radar(data_frame: pd.DataFrame, **kwargs): fig = px.line_polar(data_frame, **kwargs) fig.update_traces(fill="toself") return fig -page = vm.Page( - title="Radar", - components=[ - vm.Graph(figure=radar(wind.query("strength == '1-2'"), r="frequency", theta="direction", line_close=True)) - ], -) +wind = px.data.wind().query("strength == '1-2'") -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = radar(wind, r="frequency", theta="direction", line_close=True) diff --git a/pages/examples/sankey.py b/pages/examples/sankey.py index 21789018a898fffd11dbd2bdd4f2ca248151c072..b3f72abc83ee811f887e5c4287e5a9ac847fee30 100644 --- a/pages/examples/sankey.py +++ b/pages/examples/sankey.py @@ -1,19 +1,7 @@ -from typing import List - import pandas as pd import plotly.graph_objects as go -import vizro.models as vm -from vizro import Vizro from vizro.models.types import capture -sankey_data = pd.DataFrame( - { - "Origin": [0, 1, 0, 2, 3, 3], # indices inside labels - "Destination": [2, 3, 3, 4, 4, 5], # indices inside labels - "Value": [8, 4, 2, 8, 4, 2], - } -) - @capture("graph") def sankey( @@ -21,44 +9,35 @@ def sankey( source: str, target: str, value: str, - labels: List[str], + labels: list[str], ): - fig = go.Figure( - data=[ - go.Sankey( - node={ - "pad": 16, - "thickness": 16, - "label": labels, - }, - link={ - "source": data_frame[source], - "target": data_frame[target], - "value": data_frame[value], - "label": labels, - "color": "rgba(205, 209, 228, 0.4)", - }, - ) - ] + return go.Figure( + data=go.Sankey( + node={ + "pad": 16, + "thickness": 16, + "label": labels, + }, + link={ + "source": data_frame[source], + "target": data_frame[target], + "value": data_frame[value], + "label": labels, + "color": "rgba(205, 209, 228, 0.4)", + }, + ), + layout={"barmode": "relative"}, ) - fig.update_layout(barmode="relative") - return fig -page = vm.Page( - title="Sankey", - components=[ - vm.Graph( - figure=sankey( - sankey_data, - labels=["A1", "A2", "B1", "B2", "C1", "C2"], - source="Origin", - target="Destination", - value="Value", - ), - ), - ], +sankey_data = pd.DataFrame( + { + "Origin": [0, 1, 0, 2, 3, 3], # indices inside labels + "Destination": [2, 3, 3, 4, 4, 5], # indices inside labels + "Value": [8, 4, 2, 8, 4, 2], + } ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = sankey( + sankey_data, labels=["A1", "A2", "B1", "B2", "C1", "C2"], source="Origin", target="Destination", value="Value" +) diff --git a/pages/examples/scatter.py b/pages/examples/scatter.py index c82c95cc644fc658b9a81403ff9f6755018e55de..d48bb936ae27b8f78bbe595439e39f6ae9cf311b 100644 --- a/pages/examples/scatter.py +++ b/pages/examples/scatter.py @@ -1,13 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro iris = px.data.iris() -page = vm.Page( - title="Scatter", - components=[vm.Graph(figure=px.scatter(iris, x="sepal_width", y="sepal_length", color="species"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.scatter(iris, x="sepal_width", y="sepal_length", color="species") diff --git a/pages/examples/scatter_matrix.py b/pages/examples/scatter_matrix.py index 01b355945a5737d6f2430289c97b56874150f6e8..b162405b6f3a194482d2a0d01eb574013f7cfc9b 100644 --- a/pages/examples/scatter_matrix.py +++ b/pages/examples/scatter_matrix.py @@ -1,17 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro iris = px.data.iris() -page = vm.Page( - title="Scatter matrix", - components=[ - vm.Graph( - figure=px.scatter_matrix(iris, dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"]) - ) - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.scatter_matrix(iris, dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"]) diff --git a/pages/examples/stacked_bar.py b/pages/examples/stacked_bar.py index 81b38ac1f6baeb8f22563bd757de8e1bc324898a..f5b03fb539a1a55ebd0699aa9920d4b011cef1c2 100644 --- a/pages/examples/stacked_bar.py +++ b/pages/examples/stacked_bar.py @@ -1,14 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() - -page = vm.Page( - title="Stacked bar", - components=[vm.Graph(figure=px.histogram(tips, y="sex", x="total_bill", color="day", orientation="h"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.histogram(tips, y="sex", x="total_bill", color="day", orientation="h") diff --git a/pages/examples/stacked_column.py b/pages/examples/stacked_column.py index 68bb9eddc8bd064bbe0bd5edc0a59a1eb89bea16..f53904dfb87f3ed89ee77158af49c92604defdd9 100644 --- a/pages/examples/stacked_column.py +++ b/pages/examples/stacked_column.py @@ -1,14 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() - -page = vm.Page( - title="Stacked column", - components=[vm.Graph(figure=px.histogram(tips, x="sex", y="total_bill", color="day"))], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.histogram(tips, x="sex", y="total_bill", color="day") diff --git a/pages/examples/stepped_line.py b/pages/examples/stepped_line.py index 3b97d4d4febcd30e79016f9a2181273bead9718d..bd4e6ae064f6afe768d189c7849d5c53e26d1f7a 100644 --- a/pages/examples/stepped_line.py +++ b/pages/examples/stepped_line.py @@ -1,7 +1,5 @@ import pandas as pd -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro stepped_line_data = pd.DataFrame( { @@ -10,18 +8,4 @@ stepped_line_data = pd.DataFrame( } ) -page = vm.Page( - title="Stepped line", - components=[ - vm.Graph( - figure=px.line( - data_frame=stepped_line_data, - x="year", - y="rate", - line_shape="vh", - ), - ) - ], -) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.line(data_frame=stepped_line_data, x="year", y="rate", line_shape="vh") diff --git a/pages/examples/time_column.py b/pages/examples/time_column.py index dac0a57cafb91835fca7cae0349ef3ec090b32a6..b57a4e23f4556db5db8af2427b5745714df1f382 100644 --- a/pages/examples/time_column.py +++ b/pages/examples/time_column.py @@ -1,36 +1,16 @@ import pandas as pd -import vizro.models as vm +import plotly.graph_objects as go import vizro.plotly.express as px -from vizro import Vizro from vizro.models.types import capture -gapminder = px.data.gapminder() - @capture("graph") -def categorical_column(data_frame: pd.DataFrame, x: str, y: str): - fig = px.bar( - data_frame, - x=x, - y=y, - ) - # So ticks are aligned with bars when xaxes values are numbers (e.g. years) +def categorical_column(data_frame: pd.DataFrame, **kwargs) -> go.Figure: + fig = px.bar(data_frame, **kwargs) fig.update_xaxes(type="category") return fig -page = vm.Page( - title="Column", - components=[ - vm.Graph( - figure=categorical_column( - gapminder.query("country == 'Nigeria' and year > 1970"), - y="lifeExp", - x="year", - ) - ) - ], -) +gapminder = px.data.gapminder().query("country == 'Nigeria' and year > 1970") -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = categorical_column(gapminder, x="year", y="lifeExp") diff --git a/pages/examples/treemap.py b/pages/examples/treemap.py index ce94bdb07f113118b919db0614112f7cae1ef3f0..f130af589ed2568e97136d482e022833b1b90d88 100644 --- a/pages/examples/treemap.py +++ b/pages/examples/treemap.py @@ -1,22 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro -gapminder = px.data.gapminder() +gapminder = px.data.gapminder().query("year == 2007") -page = vm.Page( - title="Treemap", - components=[ - vm.Graph( - figure=px.treemap( - gapminder.query("year == 2007"), - path=[px.Constant("world"), "continent", "country"], - values="pop", - color="lifeExp", - ) - ), - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.treemap(gapminder, path=[px.Constant("world"), "continent", "country"], values="pop", color="lifeExp") diff --git a/pages/examples/violin.py b/pages/examples/violin.py index f3edcffe515de04cbc8da3cac5279016e27c5964..b27ee3ca3a19c49cf5aff86c4134c01874cb6506 100644 --- a/pages/examples/violin.py +++ b/pages/examples/violin.py @@ -1,15 +1,5 @@ -import vizro.models as vm import vizro.plotly.express as px -from vizro import Vizro tips = px.data.tips() -page = vm.Page( - title="Violin", - components=[ - vm.Graph(figure=px.violin(tips, y="total_bill", x="day", color="day", box=True)), - ], -) - -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = px.violin(tips, y="total_bill", x="day", color="day", box=True) diff --git a/pages/examples/waterfall.py b/pages/examples/waterfall.py index 00d925f0bc51b1c18dac26c3003ab7991676a172..75f46360431cb028c27e7643f736906074e3185f 100644 --- a/pages/examples/waterfall.py +++ b/pages/examples/waterfall.py @@ -1,51 +1,27 @@ -from typing import List - import pandas as pd import plotly.graph_objects as go -import vizro.models as vm -from vizro import Vizro from vizro.models.types import capture -waterfall_data = pd.DataFrame( - { - "x": ["Sales", "Consulting", "Net revenue", "Purchases", "Other expenses", "Profit before tax"], - "y": [60, 80, 0, -40, -20, 0], - "measure": ["relative", "relative", "total", "relative", "relative", "total"], - } -) - @capture("graph") def waterfall( data_frame: pd.DataFrame, x: str, y: str, - measure: List[str], + measure: list[str], ): - fig = go.Figure( - go.Waterfall( - x=data_frame[x], - y=data_frame[y], - measure=data_frame[measure], - ) + return go.Figure( + data=go.Waterfall(x=data_frame[x], y=data_frame[y], measure=data_frame[measure]), + layout={"showlegend": False}, ) - fig.update_layout(showlegend=False) - return fig -page = vm.Page( - title="Waterfall", - components=[ - vm.Graph( - figure=waterfall( - waterfall_data, - x="x", - y="y", - measure="measure", - ) - ) - ], +waterfall_data = pd.DataFrame( + { + "x": ["Sales", "Consulting", "Net revenue", "Purchases", "Other expenses", "Profit before tax"], + "y": [60, 80, 0, -40, -20, 0], + "measure": ["relative", "relative", "total", "relative", "relative", "total"], + } ) -dashboard = vm.Dashboard(pages=[page]) -Vizro().build(dashboard).run() +fig = waterfall(waterfall_data, x="x", y="y", measure="measure") diff --git a/pages/flow.py b/pages/flow.py index 1ab6feadfcfa2e19795cf8b47b2d431881ba5e28..bc353fd69a9b6ac674f150b44d89adc885600b47 100644 --- a/pages/flow.py +++ b/pages/flow.py @@ -1,12 +1,12 @@ """Flow charts.""" import vizro.models as vm -from custom_charts import sankey from pages._factories import waterfall_factory -from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file, sankey_data +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import sankey -sankey = vm.Page( +sankey_page = vm.Page( title="Sankey", path="flow/sankey", layout=vm.Layout(grid=PAGE_GRID), @@ -32,19 +32,21 @@ sankey = vm.Page( possible. """ ), - vm.Graph( - figure=sankey( - sankey_data, - labels=["A1", "A2", "B1", "B2", "C1", "C2"], - source="Origin", - target="Destination", - value="Value", - ), + vm.Graph(figure=sankey.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("sankey.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("sankey.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("sankey.py"), ], ) -waterfall = waterfall_factory("flow") +waterfall_page = waterfall_factory("flow") -pages = [sankey, waterfall] +pages = [sankey_page, waterfall_page] diff --git a/pages/magnitude.py b/pages/magnitude.py index f40199454b499a7dd7ad9aeeff8ab953f4f5612e..fc3b23337b7e71d2365ca57d74cba703621ce862 100644 --- a/pages/magnitude.py +++ b/pages/magnitude.py @@ -1,12 +1,11 @@ """Magnitude charts.""" import vizro.models as vm -import vizro.plotly.express as px -from custom_charts import radar -from pages._pages_utils import PAGE_GRID, gapminder, iris, make_code_clipboard_from_py_file, tips, wind +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import bar, magnitude_column, paired_bar, paired_column, parallel_coordinates, radar -bar = vm.Page( +bar_page = vm.Page( title="Bar", path="magnitude/bar", layout=vm.Layout(grid=PAGE_GRID), @@ -29,22 +28,24 @@ bar = vm.Page( descriptions below. """ ), - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" + vm.Graph(figure=bar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("bar.py", mode="vizro")] ), - x="pop", - y="country", - orientation="h", - ) + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("bar.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("bar.py"), ], ) + # Note: Code example for magnitude/column differs from time/column. The text description is the same. -column = vm.Page( +column_page = vm.Page( id="magnitude-column", path="magnitude/column", title="Column", @@ -67,20 +68,23 @@ column = vm.Page( or abbreviations with fuller descriptions below. """ ), - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" + vm.Graph(figure=magnitude_column.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("magnitude_column.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("magnitude_column.py", mode="plotly")], ), - y="pop", - x="country", - ) + ] ), - make_code_clipboard_from_py_file("magnitude_column.py"), ], ) -paired_bar = vm.Page( +paired_bar_page = vm.Page( title="Paired bar", path="magnitude/paired-bar", layout=vm.Layout(grid=PAGE_GRID), @@ -105,22 +109,23 @@ paired_bar = vm.Page( with fuller descriptions below. """ ), - vm.Graph( - figure=px.histogram( - tips, - y="day", - x="total_bill", - color="sex", - barmode="group", - orientation="h", - category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]}, - ), + vm.Graph(figure=paired_bar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("paired_bar.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("paired_bar.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("paired_bar.py"), ], ) -paired_column = vm.Page( +paired_column_page = vm.Page( title="Paired column", path="magnitude/paired-column", layout=vm.Layout(grid=PAGE_GRID), @@ -145,21 +150,23 @@ paired_column = vm.Page( with fuller descriptions below. """ ), - vm.Graph( - figure=px.histogram( - tips, - x="day", - y="total_bill", - color="sex", - barmode="group", - category_orders={"day": ["Thur", "Fri", "Sat", "Sun"]}, - ), + vm.Graph(figure=paired_column.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("paired_column.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("paired_column.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("paired_column.py"), ], ) -parallel_coordinates = vm.Page( +parallel_coordinates_page = vm.Page( path="magnitude/parallel-coordinates ", title="Parallel coordinates", layout=vm.Layout(grid=PAGE_GRID), @@ -182,16 +189,23 @@ parallel_coordinates = vm.Page( coding to distinguish between different data points or groups. """ ), - vm.Graph( - figure=px.parallel_coordinates( - iris, color="species_id", dimensions=["sepal_width", "sepal_length", "petal_width", "petal_length"] - ) + vm.Graph(figure=parallel_coordinates.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("parallel_coordinates.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("parallel_coordinates.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("parallel_coordinates.py"), ], ) -radar = vm.Page( +radar_page = vm.Page( path="magnitude/radar", title="Radar", layout=vm.Layout(grid=PAGE_GRID), @@ -209,9 +223,19 @@ radar = vm.Page( To maintain clarity, use consistent scales for all axes and clearly mark labels and data points. """ ), - vm.Graph(figure=radar(wind.query("strength == '1-2'"), r="frequency", theta="direction", line_close=True)), - make_code_clipboard_from_py_file("radar.py"), + vm.Graph(figure=radar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("radar.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("radar.py", mode="plotly")], + ), + ] + ), ], ) -pages = [bar, column, paired_bar, paired_column, parallel_coordinates, radar] +pages = [bar_page, column_page, paired_bar_page, paired_column_page, parallel_coordinates_page, radar_page] diff --git a/pages/part_to_whole.py b/pages/part_to_whole.py index fd54debede591217097d2412685e929ddf66245d..86397d1a0860d630208ff9a44b5ad85c7cd649b4 100644 --- a/pages/part_to_whole.py +++ b/pages/part_to_whole.py @@ -1,12 +1,12 @@ """Part-to-whole charts.""" import vizro.models as vm -import vizro.plotly.express as px from pages._factories import waterfall_factory -from pages._pages_utils import PAGE_GRID, funnel_data, gapminder, make_code_clipboard_from_py_file, tips +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import donut, funnel, pie, stacked_bar, stacked_column, treemap -pie = vm.Page( +pie_page = vm.Page( title="Pie", path="part-to-whole/pie", layout=vm.Layout(grid=PAGE_GRID), @@ -32,18 +32,22 @@ pie = vm.Page( difficult to accurately compare the sizes of the segments. """ ), - vm.Graph( - figure=px.pie( - tips, - values="tip", - names="day", - ) + vm.Graph(figure=pie.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("pie.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("pie.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("pie.py"), ], ) -donut = vm.Page( +donut_page = vm.Page( title="Donut", path="part-to-whole/donut", layout=vm.Layout(grid=PAGE_GRID), @@ -65,19 +69,22 @@ donut = vm.Page( to focus on the length of the arcs of the sections instead of the proportions of the segment sizes. """ ), - vm.Graph( - figure=px.pie( - tips, - values="tip", - names="day", - hole=0.4, - ) + vm.Graph(figure=donut.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("donut.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("donut.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("donut.py"), ], ) -treemap = vm.Page( +treemap_page = vm.Page( title="Treemap", path="part-to-whole/treemap", layout=vm.Layout(grid=PAGE_GRID), @@ -101,19 +108,22 @@ treemap = vm.Page( overview of the data. """ ), - vm.Graph( - figure=px.treemap( - gapminder.query("year == 2007"), - path=[px.Constant("world"), "continent", "country"], - values="pop", - color="lifeExp", - ) + vm.Graph(figure=treemap.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("treemap.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("treemap.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("treemap.py"), ], ) -stacked_bar = vm.Page( +stacked_bar_page = vm.Page( title="Stacked bar", path="part-to-whole/stacked-bar", layout=vm.Layout(grid=PAGE_GRID), @@ -139,12 +149,23 @@ stacked_bar = vm.Page( descriptions below. """ ), - vm.Graph(figure=px.histogram(tips, y="sex", x="total_bill", color="day", orientation="h")), - make_code_clipboard_from_py_file("stacked_bar.py"), + vm.Graph(figure=stacked_bar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("stacked_bar.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("stacked_bar.py", mode="plotly")], + ), + ] + ), ], ) -stacked_column = vm.Page( +stacked_column_page = vm.Page( title="Stacked column", path="part-to-whole/stacked-column", layout=vm.Layout(grid=PAGE_GRID), @@ -170,12 +191,23 @@ stacked_column = vm.Page( descriptions below. """ ), - vm.Graph(figure=px.histogram(tips, x="sex", y="total_bill", color="day")), - make_code_clipboard_from_py_file("stacked_bar.py"), + vm.Graph(figure=stacked_column.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("stacked_column.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("stacked_column.py", mode="plotly")], + ), + ] + ), ], ) -funnel = vm.Page( +funnel_page = vm.Page( title="Funnel", path="part-to-whole/funnel", layout=vm.Layout(grid=PAGE_GRID), @@ -199,11 +231,21 @@ funnel = vm.Page( sales processes, or any sequential data where you want to highlight drop-offs or reductions between stages. """ ), - vm.Graph(figure=px.funnel_area(funnel_data, names="Stage", values="Value")), - make_code_clipboard_from_py_file("funnel.py"), + vm.Graph(figure=funnel.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("funnel.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("funnel.py", mode="plotly")], + ), + ] + ), ], ) -waterfall = waterfall_factory("part-to-whole") +waterfall_page = waterfall_factory("part-to-whole") -pages = [donut, pie, treemap, stacked_bar, stacked_column, funnel, waterfall] +pages = [donut_page, pie_page, treemap_page, stacked_bar_page, stacked_column_page, funnel_page, waterfall_page] diff --git a/pages/ranking.py b/pages/ranking.py index 745a5d01f8f2bfab29e268b237da33029fa54d54..a788223d78a62ec3967d6b306ec55dee961b4651 100644 --- a/pages/ranking.py +++ b/pages/ranking.py @@ -1,11 +1,11 @@ """Ranking charts.""" import vizro.models as vm -import vizro.plotly.express as px -from pages._pages_utils import PAGE_GRID, gapminder, make_code_clipboard_from_py_file +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import ordered_bar, ordered_column -ordered_bar = vm.Page( +ordered_bar_page = vm.Page( title="Ordered bar", path="ranking/ordered-bar", layout=vm.Layout(grid=PAGE_GRID), @@ -28,21 +28,23 @@ ordered_bar = vm.Page( descriptions below. """ ), - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" - ).sort_values("pop"), - x="pop", - y="country", - orientation="h", - ) + vm.Graph(figure=ordered_bar.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("ordered_bar.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("ordered_bar.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("ordered_bar.py"), ], ) -ordered_column = vm.Page( +ordered_column_page = vm.Page( title="Ordered column", path="ranking/ordered-column", layout=vm.Layout(grid=PAGE_GRID), @@ -66,18 +68,21 @@ ordered_column = vm.Page( descriptions below. """ ), - vm.Graph( - figure=px.bar( - gapminder.query( - "year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])" - ).sort_values("pop"), - y="pop", - x="country", - ) + vm.Graph(figure=ordered_column.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("ordered_column.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("ordered_column.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("ordered_column.py"), ], ) -pages = [ordered_bar, ordered_column] +pages = [ordered_bar_page, ordered_column_page] diff --git a/pages/spatial.py b/pages/spatial.py index 8a96aba88dfff72459461a4c20519b4df8af5a91..cf14fe6270446fac18a987196282b754a6959d60 100644 --- a/pages/spatial.py +++ b/pages/spatial.py @@ -1,11 +1,11 @@ """Spatial charts.""" import vizro.models as vm -import vizro.plotly.express as px -from pages._pages_utils import PAGE_GRID, carshare, gapminder, make_code_clipboard_from_py_file +from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file +from pages.examples import bubble_map, choropleth, dot_map -choropleth = vm.Page( +choropleth_page = vm.Page( title="Choropleth", path="spatial/choropleth", layout=vm.Layout(grid=PAGE_GRID), @@ -30,19 +30,23 @@ choropleth = vm.Page( """ ), - vm.Graph( - figure=px.choropleth( - gapminder.query("year == 2007"), - locations="iso_alpha", - color="lifeExp", - hover_name="country", - ) + vm.Graph(figure=choropleth.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("choropleth.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("choropleth.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("choropleth.py"), ], ) -dot_map = vm.Page( +dot_map_page = vm.Page( title="Dot map", path="spatial/dot-map", layout=vm.Layout(grid=PAGE_GRID), @@ -66,19 +70,23 @@ dot_map = vm.Page( """ ), vm.Graph( - figure=px.scatter_map( - carshare, - lat="centroid_lat", - lon="centroid_lon", - opacity=0.5, - zoom=10, - ), + figure=dot_map.fig, + ), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("dot_map.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("dot_map.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("dot_map.py"), ], ) -bubble_map = vm.Page( +bubble_map_page = vm.Page( title="Bubble map", path="spatial/bubble-map", layout=vm.Layout(grid=PAGE_GRID), @@ -101,20 +109,21 @@ bubble_map = vm.Page( details in crowded areas. Adjust the opacity and size of your bubbles to enhance clarity. """ ), - vm.Graph( - figure=px.scatter_map( - carshare, - lat="centroid_lat", - lon="centroid_lon", - size="car_hours", - size_max=15, - opacity=0.5, - zoom=10, - ), + vm.Graph(figure=bubble_map.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("bubble_map.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("bubble_map.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("bubble_map.py"), ], ) -pages = [choropleth, dot_map, bubble_map] +pages = [choropleth_page, dot_map_page, bubble_map_page] diff --git a/pages/time.py b/pages/time.py index 16c62ecb8540b29fc24320cd008dbe287a756c7f..6fda8d3143c9fa7d325b794876e07ae769e19b73 100644 --- a/pages/time.py +++ b/pages/time.py @@ -1,21 +1,15 @@ """Time charts.""" import vizro.models as vm -import vizro.plotly.express as px -from custom_charts import categorical_column from pages._factories import column_and_line_factory, connected_scatter_factory from pages._pages_utils import ( PAGE_GRID, - gapminder, make_code_clipboard_from_py_file, - stepped_line_data, - stocks, - tasks, - tips, ) +from pages.examples import area, gantt, heatmap, line, stepped_line, time_column -line = vm.Page( +line_page = vm.Page( title="Line", path="time/line", layout=vm.Layout(grid=PAGE_GRID), @@ -38,13 +32,23 @@ line = vm.Page( same chart, try to limit yourself to 3-4 to avoid cluttering up your chart. """ ), - vm.Graph(figure=px.line(stocks, x="date", y="GOOG")), - make_code_clipboard_from_py_file("line.py"), + vm.Graph(figure=line.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("line.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("line.py", mode="plotly")], + ), + ] + ), ], ) # Note: Code example for magnitude/column differs from time/column. The text description is the same. -column = vm.Page( +column_page = vm.Page( id="time-column", path="time/column", title="Column", @@ -67,18 +71,23 @@ column = vm.Page( or abbreviations with fuller descriptions below. """ ), - vm.Graph( - figure=categorical_column( - gapminder.query("country == 'Nigeria' and year > 1970"), - y="gdpPercap", - x="year", - ) + vm.Graph(figure=time_column.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("time_column.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("time_column.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("time_column.py"), ], ) -area = vm.Page( +area_page = vm.Page( title="Area", path="time/area", layout=vm.Layout(grid=PAGE_GRID), @@ -101,15 +110,25 @@ area = vm.Page( data series in the same chart, try to limit yourself to 3-4 to maintain clarity and avoid clutter. """ ), - vm.Graph(figure=px.area(stocks, x="date", y="GOOG")), - make_code_clipboard_from_py_file("area.py"), + vm.Graph(figure=area.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("area.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("area.py", mode="plotly")], + ), + ] + ), ], ) -connected_scatter = connected_scatter_factory("time") -column_and_line = column_and_line_factory("time") +connected_scatter_page = connected_scatter_factory("time") +column_and_line_page = column_and_line_factory("time") -stepped_line = vm.Page( +stepped_line_page = vm.Page( title="Stepped line", path="time/stepped-line", layout=vm.Layout(grid=PAGE_GRID), @@ -130,19 +149,23 @@ stepped_line = vm.Page( By contrast, a line chart would suggest that changes occur gradually. """ ), - vm.Graph( - figure=px.line( - data_frame=stepped_line_data, - x="year", - y="rate", - line_shape="vh", - ), + vm.Graph(figure=stepped_line.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", + components=[make_code_clipboard_from_py_file("stepped_line.py", mode="vizro")], + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("stepped_line.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("stepped_line.py"), ], ) -heatmap = vm.Page( +heatmap_page = vm.Page( title="Heatmap", path="time/heatmap", layout=vm.Layout(grid=PAGE_GRID), @@ -164,12 +187,22 @@ heatmap = vm.Page( patterns and correlations. """ ), - vm.Graph(figure=px.density_heatmap(tips, x="day", y="size", z="tip", histfunc="avg", text_auto="$.2f")), - make_code_clipboard_from_py_file("heatmap.py"), + vm.Graph(figure=heatmap.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("heatmap.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("heatmap.py", mode="plotly")], + ), + ] + ), ], ) -gantt = vm.Page( +gantt_page = vm.Page( title="Gantt", path="time/gantt", layout=vm.Layout(grid=PAGE_GRID), @@ -193,10 +226,27 @@ it easy to monitor project status and manage interdependencies. However, they ca complex if not regularly updated, especially for large projects. """ ), - vm.Graph( - figure=px.timeline(tasks.sort_values("Start", ascending=False), x_start="Start", x_end="Finish", y="Task") + vm.Graph(figure=gantt.fig), + vm.Tabs( + tabs=[ + vm.Container( + title="Vizro dashboard", components=[make_code_clipboard_from_py_file("gantt.py", mode="vizro")] + ), + vm.Container( + title="Plotly figure", + components=[make_code_clipboard_from_py_file("gantt.py", mode="plotly")], + ), + ] ), - make_code_clipboard_from_py_file("gantt.py"), ], ) -pages = [line, column, area, connected_scatter, column_and_line, stepped_line, heatmap, gantt] +pages = [ + line_page, + column_page, + area_page, + connected_scatter_page, + column_and_line_page, + stepped_line_page, + heatmap_page, + gantt_page, +] diff --git a/requirements.in b/requirements.in index 6d95b1e4f60a3e13974fa2afded01169725ebc53..701ad04d631061bbbb6d8f48666755dba0bfd667 100644 --- a/requirements.in +++ b/requirements.in @@ -1,5 +1,7 @@ # This file is only used if you don't have hatch installed. +autoflake==2.3.1 black==24.4.2 -plotly>=5.24.0 -vizro==0.1.23 +isort==5.13.2 +plotly==5.24.1 +vizro==0.1.25 gunicorn diff --git a/requirements.txt b/requirements.txt index 120aab559c5b4cb3340b415ba01742c73141b13d..693b90a19e6303abcd1923140a86a25d27a2b1e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,21 +2,27 @@ # uv pip compile requirements.in -o requirements.txt annotated-types==0.7.0 # via pydantic +autoflake==2.3.1 + # via + # -r requirements.in + # vizro black==24.4.2 - # via -r requirements.in + # via + # -r requirements.in + # vizro blinker==1.8.2 # via flask cachelib==0.9.0 # via flask-caching certifi==2024.8.30 # via requests -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via requests click==8.1.7 # via # black # flask -dash==2.18.0 +dash==2.18.1 # via # dash-ag-grid # dash-bootstrap-components @@ -41,17 +47,17 @@ flask-caching==2.3.0 # via vizro gunicorn==23.0.0 # via -r requirements.in -idna==3.8 +idna==3.10 # via requests -importlib-metadata==8.4.0 - # via - # dash - # flask +importlib-metadata==8.5.0 + # via dash +isort==5.13.2 + # via -r requirements.in itsdangerous==2.2.0 # via flask jinja2==3.1.4 # via flask -markupsafe==2.1.5 +markupsafe==3.0.2 # via # jinja2 # werkzeug @@ -59,38 +65,39 @@ mypy-extensions==1.0.0 # via black nest-asyncio==1.6.0 # via dash -numpy==2.0.2 +numpy==2.1.2 # via pandas packaging==24.1 # via # black # gunicorn # plotly -pandas==2.2.2 +pandas==2.2.3 # via vizro pathspec==0.12.1 # via black platformdirs==4.2.2 # via black -plotly==5.24.0 +plotly==5.24.1 # via # -r requirements.in # dash -pydantic==2.8.2 + # vizro +pydantic==2.9.2 # via vizro -pydantic-core==2.20.1 +pydantic-core==2.23.4 # via pydantic +pyflakes==3.2.0 + # via autoflake python-dateutil==2.9.0.post0 # via pandas -pytz==2024.1 +pytz==2024.2 # via pandas requests==2.32.3 # via dash retrying==1.3.4 # via dash -ruff==0.6.3 - # via vizro -setuptools==74.1.2 +setuptools==75.3.0 # via dash six==1.16.0 # via @@ -98,25 +105,22 @@ six==1.16.0 # retrying tenacity==9.0.0 # via plotly -tomli==2.0.1 - # via black typing-extensions==4.12.2 # via - # black # dash # pydantic # pydantic-core -tzdata==2024.1 +tzdata==2024.2 # via pandas -urllib3==2.2.2 +urllib3==2.2.3 # via requests -vizro==0.1.23 +vizro==0.1.25 # via -r requirements.in -werkzeug==3.0.4 +werkzeug==3.0.6 # via # dash # flask wrapt==1.16.0 # via vizro -zipp==3.20.1 +zipp==3.20.2 # via importlib-metadata