Skip to content

Commit 8c0b821

Browse files
committed
wip: add a new legendgroup parameter
1 parent 75ea775 commit 8c0b821

20 files changed

Lines changed: 140 additions & 25 deletions

cicd_utils/ridgeplot_examples/_lincoln_weather.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ def main(
2727

2828
fig = ridgeplot(
2929
samples=samples,
30-
labels=[["Min Temperature [F]", "Max Temperature [F]"]] * len(months),
30+
labels=[["Min Temperatures", "Max Temperatures"]] * len(months),
3131
row_labels=months,
32+
legendgroup=True,
3233
colorscale="Inferno",
3334
color_discrete_map=color_discrete_map,
3435
bandwidth=4,
@@ -46,7 +47,12 @@ def main(
4647
xaxis_gridwidth=2,
4748
yaxis_title="Month",
4849
xaxis_title="Temperature [F]",
49-
showlegend=False,
50+
legend=dict(
51+
yanchor="top",
52+
y=0.99,
53+
xanchor="right",
54+
x=0.99,
55+
),
5056
)
5157

5258
return fig

cicd_utils/ridgeplot_examples/_lincoln_weather_red_blue.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
def main() -> go.Figure:
1212
fig = lincoln_weather(
1313
color_discrete_map={
14-
"Min Temperature [F]": "deepskyblue",
15-
"Max Temperature [F]": "orangered",
14+
"Min Temperatures": "deepskyblue",
15+
"Max Temperatures": "orangered",
1616
}
1717
)
1818
return fig
6.05 KB
Loading
5.88 KB
Loading

docs/getting_started/getting_started.md

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ samples = [
134134
# And finish by styling it up to your liking!
135135
fig = ridgeplot(
136136
samples=samples,
137-
labels=[["Min Temperature [F]", "Max Temperature [F]"]] * len(months),
137+
labels=[["Min Temperatures", "Max Temperatures"]] * len(months),
138138
row_labels=months,
139+
legendgroup=True,
139140
colorscale="Inferno",
140141
bandwidth=4,
141142
kde_points=np.linspace(-40, 110, 400),
@@ -152,7 +153,12 @@ fig.update_layout(
152153
xaxis_gridwidth=2,
153154
yaxis_title="Month",
154155
xaxis_title="Temperature [F]",
155-
showlegend=False,
156+
legend=dict(
157+
yanchor="top",
158+
y=0.99,
159+
xanchor="right",
160+
x=0.99,
161+
),
156162
)
157163
fig.show()
158164
```
@@ -229,14 +235,14 @@ Finally, we can pass the {py:paramref}`~ridgeplot.ridgeplot.samples` list to the
229235
```python
230236
fig = ridgeplot(
231237
samples=samples,
232-
labels=[["Min Temperature [F]", "Max Temperature [F]"]] * len(months),
238+
labels=[["Min Temperatures", "Max Temperatures"]] * len(months),
233239
row_labels=months,
240+
legendgroup=True,
234241
colorscale="Inferno",
235242
bandwidth=4,
236243
kde_points=np.linspace(-40, 110, 400),
237244
spacing=0.3,
238245
)
239-
240246
fig.update_layout(
241247
title="Minimum and maximum daily temperatures in Lincoln, NE (2016)",
242248
height=600,
@@ -248,7 +254,12 @@ fig.update_layout(
248254
xaxis_gridwidth=2,
249255
yaxis_title="Month",
250256
xaxis_title="Temperature [F]",
251-
showlegend=False,
257+
legend=dict(
258+
yanchor="top",
259+
y=0.99,
260+
xanchor="right",
261+
x=0.99,
262+
),
252263
)
253264
fig.show()
254265
```
@@ -277,8 +288,8 @@ fig = ridgeplot(
277288
# addition of `color_discrete_map`
278289
# ...
279290
color_discrete_map={
280-
"Min Temperature [F]": "deepskyblue",
281-
"Max Temperature [F]": "orangered",
291+
"Min Temperatures": "deepskyblue",
292+
"Max Temperatures": "orangered",
282293
}
283294
# ...
284295
)

src/ridgeplot/_figure_factory.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
SolidColormode,
1414
compute_solid_colors,
1515
)
16+
from ridgeplot._obj.legendcontext import LegendContextManager
1617
from ridgeplot._obj.traces import get_trace_cls
1718
from ridgeplot._obj.traces.base import ColoringContext
1819
from ridgeplot._types import (
@@ -123,6 +124,7 @@ def create_ridgeplot(
123124
trace_labels: LabelsArray | ShallowLabelsArray | None,
124125
trace_types: TraceTypesArray | ShallowTraceTypesArray | TraceType,
125126
row_labels: Collection[str] | None | Literal[False],
127+
legendgroup: bool,
126128
colorscale: ColorScale | Collection[Color] | str | None,
127129
colormode: Literal["fillgradient"] | SolidColormode,
128130
color_discrete_map: dict[str, str] | None,
@@ -176,6 +178,8 @@ def create_ridgeplot(
176178
# --- Build the figure
177179
# ==============================================================
178180

181+
legend_ctx_manager = LegendContextManager(legendgroup=legendgroup)
182+
179183
interpolation_ctx = InterpolationContext(
180184
densities=densities,
181185
n_rows=n_rows,
@@ -209,7 +213,7 @@ def create_ridgeplot(
209213
):
210214
trace_drawer = get_trace_cls(trace_type)(
211215
trace=trace,
212-
label=label,
216+
legend_ctx=legend_ctx_manager.get_legend_ctx(label=label),
213217
solid_color=color,
214218
zorder=ith_trace,
215219
y_base=y_base,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from __future__ import annotations
2+
3+
import dataclasses
4+
from typing import Any, TypedDict
5+
6+
7+
class Font(TypedDict, total=False):
8+
# plotly/graph_objs/scatter/legendgrouptitle/_font.py
9+
color: str | None
10+
family: str | None
11+
lineposition: str | None
12+
shadow: str | None
13+
size: int | float | None
14+
style: str | None
15+
textcase: str | None
16+
variant: str | None
17+
weight: int | None
18+
19+
20+
class Legendgrouptitle(TypedDict, total=False):
21+
# plotly/graph_objs/scatter/_legendgrouptitle.py
22+
text: str | None
23+
font: Font | None
24+
25+
26+
@dataclasses.dataclass
27+
class LegendContext:
28+
name: str
29+
showlegend: bool
30+
legendgroup: str | int | float | None = None
31+
legendgrouptitle: Legendgrouptitle | None = None
32+
33+
@property
34+
def trace_kwargs(self) -> dict[str, Any]:
35+
return dataclasses.asdict(self)
36+
37+
38+
class LegendContextManager:
39+
def __init__(self, legendgroup: bool) -> None:
40+
super().__init__()
41+
self.legendgroup = legendgroup
42+
self._seen_labels: set[str] = set()
43+
44+
def get_legend_ctx(self, label: str) -> LegendContext:
45+
if not self.legendgroup:
46+
return LegendContext(name=label, showlegend=True)
47+
if label not in self._seen_labels:
48+
self._seen_labels.add(label)
49+
return LegendContext(
50+
name=label,
51+
showlegend=True,
52+
legendgroup=label,
53+
# FIXME: This doesn't seem to work as expected
54+
# legendgrouptitle=Legendgrouptitle(text=label),
55+
)
56+
return LegendContext(
57+
name=label,
58+
showlegend=False,
59+
legendgroup=label,
60+
)

src/ridgeplot/_obj/traces/area.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def draw(self, fig: go.Figure, coloring_ctx: ColoringContext) -> go.Figure:
6868
hoverinfo="skip",
6969
# z-order (higher z-order means the trace is drawn on top)
7070
zorder=self.zorder,
71+
legendgroup=self.legend_ctx.legendgroup,
7172
)
7273
)
7374
fig.add_trace(

src/ridgeplot/_obj/traces/base.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from plotly import graph_objects as go
1313

1414
from ridgeplot._color.interpolation import InterpolationContext
15+
from ridgeplot._obj.legendcontext import LegendContext
1516
from ridgeplot._types import Color, ColorScale, DensityTrace
1617

1718

@@ -24,7 +25,7 @@
2425
string below, but it's not quite the same... (see '.7~r' as well)
2526
"""
2627

27-
DEFAULT_HOVERTEMPLATE = (
28+
_DEFAULT_HOVERTEMPLATE = (
2829
f"(%{{x:{_D3HF}}}, %{{customdata[0]:{_D3HF}}})"
2930
"<br>"
3031
"<extra>%{fullData.name}</extra>"
@@ -56,7 +57,7 @@ def __init__(
5657
self,
5758
*, # kw only
5859
trace: DensityTrace,
59-
label: str,
60+
legend_ctx: LegendContext,
6061
solid_color: str,
6162
zorder: int,
6263
# Constant over the trace's row
@@ -67,7 +68,7 @@ def __init__(
6768
):
6869
super().__init__()
6970
self.x, self.y = zip(*trace, strict=True)
70-
self.label = label
71+
self.legend_ctx = legend_ctx
7172
self.solid_color = solid_color
7273
self.zorder = zorder
7374
self.y_base = y_base
@@ -79,12 +80,10 @@ def _common_trace_kwargs(self) -> dict[str, Any]:
7980
"""Return common trace kwargs."""
8081
return dict(
8182
# Legend information
82-
name=self.label,
83-
# legendgroup=self.label,
84-
# legendgrouptitle_text=self.label,
83+
**self.legend_ctx.trace_kwargs,
8584
# Hover information
8685
customdata=[[y_i] for y_i in self.y],
87-
hovertemplate=DEFAULT_HOVERTEMPLATE,
86+
hovertemplate=_DEFAULT_HOVERTEMPLATE,
8887
# z-order (higher z-order means the trace is drawn on top)
8988
zorder=self.zorder,
9089
)

src/ridgeplot/_ridgeplot.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def ridgeplot(
102102
trace_type: TraceTypesArray | ShallowTraceTypesArray | TraceType | None = None,
103103
labels: LabelsArray | ShallowLabelsArray | None = None,
104104
row_labels: Collection[str] | None | Literal[False] = None,
105+
legendgroup: bool = False, # TODO: document and rename to smth better!
105106
# KDE parameters
106107
kernel: str = "gau",
107108
bandwidth: KDEBandwidth = "normal_reference",
@@ -503,6 +504,7 @@ def ridgeplot(
503504
trace_labels=labels,
504505
trace_types=trace_type,
505506
row_labels=row_labels,
507+
legendgroup=legendgroup,
506508
colorscale=colorscale,
507509
colormode=colormode,
508510
color_discrete_map=color_discrete_map,

0 commit comments

Comments
 (0)