Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 107 additions & 29 deletions plugins/plotly-express/docs/sub-plots.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,94 @@ Create a series of plots as subplots, all providing unique perspectives on the d

```python order=tipping_plots,tips
import deephaven.plot.express as dx
tips = dx.data.tips() # import a ticking version of the Tips dataset

tips = dx.data.tips() # import a ticking version of the Tips dataset

# create 4 plots from within make_subplots
tipping_plots = dx.make_subplots(
dx.scatter(tips, x="TotalBill", y="Tip", by="Sex",
title="Tip amount by total bill"),
dx.violin(tips, y="TotalBill", by="Day",
title="Total bill distribution by day"),
dx.scatter(
tips, x="TotalBill", y="Tip", by="Sex", title="Tip amount by total bill"
),
dx.violin(tips, y="TotalBill", by="Day", title="Total bill distribution by day"),
dx.pie(
tips
.count_by("Count", by=["Sex", "Smoker"])
tips.count_by("Count", by=["Sex", "Smoker"])
.update_view("SmokerStatus = Smoker == `No` ? `non-smoker` : `smoker`")
.update_view("SmokerLabel = Sex + ` ` + SmokerStatus"),
names="SmokerLabel", values="Count",
title="Total bill by sex and smoking status"),
dx.bar(tips
.view(["TotalBill", "Tip", "Day"])
.avg_by("Day"),
x="Day", y=["TotalBill", "Tip"],
title="Average tip as a fraction of total bill"),
rows=2, cols=2, shared_xaxes=False, shared_yaxes=False
names="SmokerLabel",
values="Count",
title="Total bill by sex and smoking status",
),
dx.bar(
tips.view(["TotalBill", "Tip", "Day"]).avg_by("Day"),
x="Day",
y=["TotalBill", "Tip"],
title="Average tip as a fraction of total bill",
),
rows=2,
cols=2,
shared_xaxes=False,
shared_yaxes=False,
)
```

### Adding Subplot Titles

You can add titles to individual subplots using the `subplot_titles` parameter. Provide a list or tuple of titles, ordered from left to right, top to bottom.

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx

tips = dx.data.tips()

lunch_tips = tips.where("Time = `Lunch`")
dinner_tips = tips.where("Time = `Dinner`")

# Add titles to subplots
tipping_plots = dx.make_subplots(
dx.scatter(lunch_tips, x="TotalBill", y="Tip"),
dx.scatter(dinner_tips, x="TotalBill", y="Tip"),
rows=2,
subplot_titles=["Lunch Tips", "Dinner Tips"],
)
```

### Using Existing Titles

You can automatically use the titles from the original figures as subplot titles by setting `titles_as_subtitles=True`.

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx

tips = dx.data.tips()

lunch_tips = tips.where("Time = `Lunch`")
dinner_tips = tips.where("Time = `Dinner`")

# Figures with titles
lunch_chart = dx.scatter(lunch_tips, x="TotalBill", y="Tip", title="Lunch Tips")
dinner_chart = dx.scatter(dinner_tips, x="TotalBill", y="Tip", title="Dinner Tips")

# Use existing titles as subplot titles
tipping_plots = dx.make_subplots(
lunch_chart, dinner_chart, rows=2, titles_as_subtitles=True
)
```

### Adding an Overall Title

You can add an overall title to the combined subplot figure using the `title` parameter.

```python order=tipping_plots,tips
import deephaven.plot.express as dx

tips = dx.data.tips()

tipping_plots = dx.make_subplots(
dx.scatter(tips, x="TotalBill", y="Tip", by="Day"),
dx.histogram(tips, x="TotalBill"),
rows=2,
subplot_titles=["Daily Patterns", "Distribution"],
title="Tipping Analysis",
)
```

Expand All @@ -45,7 +112,8 @@ When one axis is adjusted, all axes are adjusted to match.

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx
tips = dx.data.tips() # import a ticking version of the Tips dataset

tips = dx.data.tips() # import a ticking version of the Tips dataset

# filter the tips dataset for separate lunch and dinner charts
lunch_tips = tips.where("Time = `Lunch`")
Expand All @@ -55,7 +123,9 @@ dinner_tips = tips.where("Time = `Dinner`")
tipping_plots = dx.make_subplots(
dx.scatter(lunch_tips, x="TotalBill", y="Tip", labels={"Tip": "Lunch Tips"}),
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
rows=2, shared_yaxes="all", shared_xaxes="all"
rows=2,
shared_yaxes="all",
shared_xaxes="all",
)
```

Expand All @@ -66,7 +136,8 @@ When one y-axis is adjusted, all axes along the same row are adjusted to match.

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx
tips = dx.data.tips() # import a ticking version of the Tips dataset

tips = dx.data.tips() # import a ticking version of the Tips dataset

# filter the tips dataset for separate lunch and dinner charts
lunch_tips = tips.where("Time = `Lunch`")
Expand All @@ -75,16 +146,18 @@ dinner_tips = tips.where("Time = `Dinner`")
# create chart that shares y axes along the row
tipping_plots = dx.make_subplots(
dx.scatter(lunch_tips, x="TotalBill", y="Tip", labels={"Tip": "Lunch Tips"}),
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
cols=2, shared_yaxes=True
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
cols=2,
shared_yaxes=True,
)
```

To share the y axes along the same column, set `shared_yaxes` to `"columns"`.

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx
tips = dx.data.tips() # import a ticking version of the Tips dataset

tips = dx.data.tips() # import a ticking version of the Tips dataset

# filter the tips dataset for separate lunch and dinner charts
lunch_tips = tips.where("Time = `Lunch`")
Expand All @@ -93,8 +166,9 @@ dinner_tips = tips.where("Time = `Dinner`")
# create chart that shares y axes along the column
tipping_plots = dx.make_subplots(
dx.scatter(lunch_tips, x="TotalBill", y="Tip", labels={"Tip": "Lunch Tips"}),
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
rows=2, shared_yaxes="columns"
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
rows=2,
shared_yaxes="columns",
)
```

Expand All @@ -105,7 +179,8 @@ When one x-axis is adjusted, all axes along the same column are adjusted to matc

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx
tips = dx.data.tips() # import a ticking version of the Tips dataset

tips = dx.data.tips() # import a ticking version of the Tips dataset

# filter the tips dataset for separate lunch and dinner charts
lunch_tips = tips.where("Time = `Lunch`")
Expand All @@ -114,16 +189,18 @@ dinner_tips = tips.where("Time = `Dinner`")
# create chart that shares x axes along the column
tipping_plots = dx.make_subplots(
dx.scatter(lunch_tips, x="TotalBill", y="Tip", labels={"Tip": "Lunch Tips"}),
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
rows=2, shared_xaxes=True
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
rows=2,
shared_xaxes=True,
)
```

To share the x axes along the same column, set `shared_yaxes` to `"columns"`.

```python order=tipping_plots,lunch_tips,dinner_tips
import deephaven.plot.express as dx
tips = dx.data.tips() # import a ticking version of the Tips dataset

tips = dx.data.tips() # import a ticking version of the Tips dataset

# filter the tips dataset for separate lunch and dinner charts
lunch_tips = tips.where("Time = `Lunch`")
Expand All @@ -132,8 +209,9 @@ dinner_tips = tips.where("Time = `Dinner`")
# create chart that shares x axes along the row
tipping_plots = dx.make_subplots(
dx.scatter(lunch_tips, x="TotalBill", y="Tip", labels={"Tip": "Lunch Tips"}),
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
cols=2, shared_xaxes="rows"
dx.scatter(dinner_tips, x="TotalBill", y="Tip", labels={"Tip": "Dinner Tips"}),
cols=2,
shared_xaxes="rows",
)
```

Expand Down
21 changes: 21 additions & 0 deletions plugins/plotly-express/src/deephaven/plot/express/plots/_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@ def atomic_layer(
specs: list[LayerSpecDict] | None = None,
unsafe_update_figure: Callable = default_callback,
remove_legend_title: bool = False,
subplot_annotations: list[dict] | None = None,
overall_title: str | None = None,
) -> DeephavenFigure:
"""
Layers the provided figures. This is an atomic version of layer, so the
Expand All @@ -460,6 +462,10 @@ def atomic_layer(
should be kept, but is necessary for other layering and subplotting as
they may not use the same plot by (and similar) columns, so the legend
title would be incorrect.
subplot_annotations:
List of annotation dictionaries to add to the layout for subplot titles.
overall_title:
Overall title to set for the figure.

Returns:
The layered chart
Expand Down Expand Up @@ -527,6 +533,17 @@ def atomic_layer(
if remove_legend_title:
new_fig.update_layout(legend_title_text=None)

# Add subplot annotations if provided
if subplot_annotations:
existing_annotations = (
list(new_fig.layout.annotations) if new_fig.layout.annotations else []
)
new_fig.update_layout(annotations=existing_annotations + subplot_annotations)

# Add overall title if provided
if overall_title:
new_fig.update_layout(title=overall_title)

update_wrapper = partial(unsafe_figure_update_wrapper, unsafe_update_figure)

return update_wrapper(
Expand All @@ -546,6 +563,7 @@ def layer(
which_layout: int | None = None,
specs: list[LayerSpecDict] | None = None,
unsafe_update_figure: Callable = default_callback,
title: str | None = None,
) -> DeephavenFigure:
"""Layers the provided figures. Be default, the layouts are sequentially
applied, so the layouts of later figures will override the layouts of early
Expand All @@ -571,6 +589,8 @@ def layer(
Used to add any custom changes to the underlying plotly figure. Note that
the existing data traces should not be removed. This may lead to unexpected
behavior if traces are modified in a way that break data mappings.
title:
Overall title to set for the figure.

Returns:
The layered chart
Expand All @@ -588,6 +608,7 @@ def layer(
# remove the legend title as it is likely incorrect
remove_legend_title=True,
unsafe_update_figure=unsafe_update_figure,
overall_title=title,
)

exec_ctx = make_user_exec_ctx()
Expand Down
Loading