xarray-plotly 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,203 @@
1
+ """
2
+ Configuration for xarray_plotly.
3
+
4
+ This module provides a global configuration system similar to xarray and pandas,
5
+ allowing users to customize label extraction and slot assignment behavior.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from contextlib import contextmanager
11
+ from dataclasses import dataclass, field
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ if TYPE_CHECKING:
15
+ from collections.abc import Generator
16
+
17
+
18
+ # Default slot orders per plot type
19
+ DEFAULT_SLOT_ORDERS: dict[str, tuple[str, ...]] = {
20
+ "line": (
21
+ "x",
22
+ "color",
23
+ "line_dash",
24
+ "symbol",
25
+ "facet_col",
26
+ "facet_row",
27
+ "animation_frame",
28
+ ),
29
+ "bar": ("x", "color", "pattern_shape", "facet_col", "facet_row", "animation_frame"),
30
+ "area": (
31
+ "x",
32
+ "color",
33
+ "pattern_shape",
34
+ "facet_col",
35
+ "facet_row",
36
+ "animation_frame",
37
+ ),
38
+ "scatter": (
39
+ "x",
40
+ "color",
41
+ "symbol",
42
+ "facet_col",
43
+ "facet_row",
44
+ "animation_frame",
45
+ ),
46
+ "imshow": ("y", "x", "facet_col", "animation_frame"),
47
+ "box": ("x", "color", "facet_col", "facet_row", "animation_frame"),
48
+ }
49
+
50
+
51
+ @dataclass
52
+ class Options:
53
+ """
54
+ Configuration options for xarray_plotly.
55
+
56
+ Attributes
57
+ ----------
58
+ label_use_long_name : bool
59
+ Use `long_name` attribute for labels. Default True.
60
+ label_use_standard_name : bool
61
+ Fall back to `standard_name` if `long_name` not available. Default True.
62
+ label_include_units : bool
63
+ Append units to labels. Default True.
64
+ label_unit_format : str
65
+ Format string for units. Use `{units}` as placeholder. Default "[{units}]".
66
+ slot_orders : dict
67
+ Slot orders per plot type. Keys are plot types, values are tuples of slot names.
68
+ """
69
+
70
+ label_use_long_name: bool = True
71
+ label_use_standard_name: bool = True
72
+ label_include_units: bool = True
73
+ label_unit_format: str = "[{units}]"
74
+ slot_orders: dict[str, tuple[str, ...]] = field(
75
+ default_factory=lambda: dict(DEFAULT_SLOT_ORDERS)
76
+ )
77
+
78
+ def to_dict(self) -> dict[str, Any]:
79
+ """Return options as a dictionary."""
80
+ return {
81
+ "label_use_long_name": self.label_use_long_name,
82
+ "label_use_standard_name": self.label_use_standard_name,
83
+ "label_include_units": self.label_include_units,
84
+ "label_unit_format": self.label_unit_format,
85
+ "slot_orders": self.slot_orders,
86
+ }
87
+
88
+
89
+ # Global options instance
90
+ _options = Options()
91
+
92
+
93
+ def get_options() -> dict[str, Any]:
94
+ """
95
+ Get the current xarray_plotly options.
96
+
97
+ Returns
98
+ -------
99
+ dict
100
+ Dictionary of current option values.
101
+
102
+ Examples
103
+ --------
104
+ >>> from xarray_plotly import config
105
+ >>> config.get_options()
106
+ {'label_use_long_name': True, 'label_include_units': True, ...}
107
+ """
108
+ return _options.to_dict()
109
+
110
+
111
+ @contextmanager
112
+ def set_options(
113
+ *,
114
+ label_use_long_name: bool | None = None,
115
+ label_use_standard_name: bool | None = None,
116
+ label_include_units: bool | None = None,
117
+ label_unit_format: str | None = None,
118
+ slot_orders: dict[str, tuple[str, ...]] | None = None,
119
+ ) -> Generator[None, None, None]:
120
+ """
121
+ Set xarray_plotly options globally or as a context manager.
122
+
123
+ Parameters
124
+ ----------
125
+ label_use_long_name : bool, optional
126
+ Use `long_name` attribute for labels.
127
+ label_use_standard_name : bool, optional
128
+ Fall back to `standard_name` if `long_name` not available.
129
+ label_include_units : bool, optional
130
+ Append units to labels.
131
+ label_unit_format : str, optional
132
+ Format string for units. Use `{units}` as placeholder.
133
+ slot_orders : dict, optional
134
+ Slot orders per plot type.
135
+
136
+ Yields
137
+ ------
138
+ None
139
+ When used as a context manager, yields nothing.
140
+
141
+ Examples
142
+ --------
143
+ Set globally:
144
+
145
+ >>> from xarray_plotly import config
146
+ >>> config.set_options(label_include_units=False)
147
+
148
+ Use as context manager:
149
+
150
+ >>> with config.set_options(label_include_units=False):
151
+ ... fig = xpx(da).line() # No units in labels
152
+ >>> # Units are back after the context
153
+ """
154
+ # Store old values
155
+ old_values = {
156
+ "label_use_long_name": _options.label_use_long_name,
157
+ "label_use_standard_name": _options.label_use_standard_name,
158
+ "label_include_units": _options.label_include_units,
159
+ "label_unit_format": _options.label_unit_format,
160
+ "slot_orders": dict(_options.slot_orders),
161
+ }
162
+
163
+ # Apply new values (modify in place to keep reference)
164
+ if label_use_long_name is not None:
165
+ _options.label_use_long_name = label_use_long_name
166
+ if label_use_standard_name is not None:
167
+ _options.label_use_standard_name = label_use_standard_name
168
+ if label_include_units is not None:
169
+ _options.label_include_units = label_include_units
170
+ if label_unit_format is not None:
171
+ _options.label_unit_format = label_unit_format
172
+ if slot_orders is not None:
173
+ _options.slot_orders = dict(slot_orders)
174
+
175
+ try:
176
+ yield
177
+ finally:
178
+ # Restore old values (modify in place)
179
+ _options.label_use_long_name = old_values["label_use_long_name"]
180
+ _options.label_use_standard_name = old_values["label_use_standard_name"]
181
+ _options.label_include_units = old_values["label_include_units"]
182
+ _options.label_unit_format = old_values["label_unit_format"]
183
+ _options.slot_orders = old_values["slot_orders"]
184
+
185
+
186
+ def notebook(renderer: str = "notebook") -> None:
187
+ """
188
+ Configure Plotly for Jupyter notebook rendering.
189
+
190
+ Parameters
191
+ ----------
192
+ renderer : str, optional
193
+ The Plotly renderer to use. Default is "notebook".
194
+ Other options include "jupyterlab", "colab", "kaggle", etc.
195
+
196
+ Examples
197
+ --------
198
+ >>> from xarray_plotly import config
199
+ >>> config.notebook() # Configure for Jupyter notebooks
200
+ """
201
+ import plotly.io as pio
202
+
203
+ pio.renderers.default = renderer
@@ -0,0 +1,448 @@
1
+ """
2
+ Plotly Express plotting functions for DataArray objects.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ import plotly.express as px
10
+
11
+ from xarray_plotly.common import (
12
+ SlotValue,
13
+ assign_slots,
14
+ auto,
15
+ build_labels,
16
+ get_label,
17
+ get_value_col,
18
+ to_dataframe,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ import plotly.graph_objects as go
23
+ from xarray import DataArray
24
+
25
+
26
+ def line(
27
+ darray: DataArray,
28
+ *,
29
+ x: SlotValue = auto,
30
+ color: SlotValue = auto,
31
+ line_dash: SlotValue = auto,
32
+ symbol: SlotValue = auto,
33
+ facet_col: SlotValue = auto,
34
+ facet_row: SlotValue = auto,
35
+ animation_frame: SlotValue = auto,
36
+ **px_kwargs: Any,
37
+ ) -> go.Figure:
38
+ """
39
+ Create an interactive line plot from a DataArray.
40
+
41
+ The y-axis shows DataArray values. Dimensions fill slots in order:
42
+ x -> color -> line_dash -> symbol -> facet_col -> facet_row -> animation_frame
43
+
44
+ Parameters
45
+ ----------
46
+ darray
47
+ The DataArray to plot.
48
+ x
49
+ Dimension for x-axis. Default: first dimension.
50
+ color
51
+ Dimension for color grouping. Default: second dimension.
52
+ line_dash
53
+ Dimension for line dash style. Default: third dimension.
54
+ symbol
55
+ Dimension for marker symbol. Default: fourth dimension.
56
+ facet_col
57
+ Dimension for subplot columns. Default: fifth dimension.
58
+ facet_row
59
+ Dimension for subplot rows. Default: sixth dimension.
60
+ animation_frame
61
+ Dimension for animation. Default: seventh dimension.
62
+ **px_kwargs
63
+ Additional arguments passed to `plotly.express.line()`.
64
+
65
+ Returns
66
+ -------
67
+ plotly.graph_objects.Figure
68
+ """
69
+ slots = assign_slots(
70
+ list(darray.dims),
71
+ "line",
72
+ x=x,
73
+ color=color,
74
+ line_dash=line_dash,
75
+ symbol=symbol,
76
+ facet_col=facet_col,
77
+ facet_row=facet_row,
78
+ animation_frame=animation_frame,
79
+ )
80
+
81
+ df = to_dataframe(darray)
82
+ value_col = get_value_col(darray)
83
+ labels = {**build_labels(darray, slots, value_col), **px_kwargs.pop("labels", {})}
84
+
85
+ return px.line(
86
+ df,
87
+ x=slots.get("x"),
88
+ y=value_col,
89
+ color=slots.get("color"),
90
+ line_dash=slots.get("line_dash"),
91
+ symbol=slots.get("symbol"),
92
+ facet_col=slots.get("facet_col"),
93
+ facet_row=slots.get("facet_row"),
94
+ animation_frame=slots.get("animation_frame"),
95
+ labels=labels,
96
+ **px_kwargs,
97
+ )
98
+
99
+
100
+ def bar(
101
+ darray: DataArray,
102
+ *,
103
+ x: SlotValue = auto,
104
+ color: SlotValue = auto,
105
+ pattern_shape: SlotValue = auto,
106
+ facet_col: SlotValue = auto,
107
+ facet_row: SlotValue = auto,
108
+ animation_frame: SlotValue = auto,
109
+ **px_kwargs: Any,
110
+ ) -> go.Figure:
111
+ """
112
+ Create an interactive bar chart from a DataArray.
113
+
114
+ The y-axis shows DataArray values. Dimensions fill slots in order:
115
+ x -> color -> pattern_shape -> facet_col -> facet_row -> animation_frame
116
+
117
+ Parameters
118
+ ----------
119
+ darray
120
+ The DataArray to plot.
121
+ x
122
+ Dimension for x-axis. Default: first dimension.
123
+ color
124
+ Dimension for color grouping. Default: second dimension.
125
+ pattern_shape
126
+ Dimension for bar fill pattern. Default: third dimension.
127
+ facet_col
128
+ Dimension for subplot columns. Default: fourth dimension.
129
+ facet_row
130
+ Dimension for subplot rows. Default: fifth dimension.
131
+ animation_frame
132
+ Dimension for animation. Default: sixth dimension.
133
+ **px_kwargs
134
+ Additional arguments passed to `plotly.express.bar()`.
135
+
136
+ Returns
137
+ -------
138
+ plotly.graph_objects.Figure
139
+ """
140
+ slots = assign_slots(
141
+ list(darray.dims),
142
+ "bar",
143
+ x=x,
144
+ color=color,
145
+ pattern_shape=pattern_shape,
146
+ facet_col=facet_col,
147
+ facet_row=facet_row,
148
+ animation_frame=animation_frame,
149
+ )
150
+
151
+ df = to_dataframe(darray)
152
+ value_col = get_value_col(darray)
153
+ labels = {**build_labels(darray, slots, value_col), **px_kwargs.pop("labels", {})}
154
+
155
+ return px.bar(
156
+ df,
157
+ x=slots.get("x"),
158
+ y=value_col,
159
+ color=slots.get("color"),
160
+ pattern_shape=slots.get("pattern_shape"),
161
+ facet_col=slots.get("facet_col"),
162
+ facet_row=slots.get("facet_row"),
163
+ animation_frame=slots.get("animation_frame"),
164
+ labels=labels,
165
+ **px_kwargs,
166
+ )
167
+
168
+
169
+ def area(
170
+ darray: DataArray,
171
+ *,
172
+ x: SlotValue = auto,
173
+ color: SlotValue = auto,
174
+ pattern_shape: SlotValue = auto,
175
+ facet_col: SlotValue = auto,
176
+ facet_row: SlotValue = auto,
177
+ animation_frame: SlotValue = auto,
178
+ **px_kwargs: Any,
179
+ ) -> go.Figure:
180
+ """
181
+ Create an interactive stacked area chart from a DataArray.
182
+
183
+ The y-axis shows DataArray values. Dimensions fill slots in order:
184
+ x -> color -> pattern_shape -> facet_col -> facet_row -> animation_frame
185
+
186
+ Parameters
187
+ ----------
188
+ darray
189
+ The DataArray to plot.
190
+ x
191
+ Dimension for x-axis. Default: first dimension.
192
+ color
193
+ Dimension for color/stacking. Default: second dimension.
194
+ pattern_shape
195
+ Dimension for fill pattern. Default: third dimension.
196
+ facet_col
197
+ Dimension for subplot columns. Default: fourth dimension.
198
+ facet_row
199
+ Dimension for subplot rows. Default: fifth dimension.
200
+ animation_frame
201
+ Dimension for animation. Default: sixth dimension.
202
+ **px_kwargs
203
+ Additional arguments passed to `plotly.express.area()`.
204
+
205
+ Returns
206
+ -------
207
+ plotly.graph_objects.Figure
208
+ """
209
+ slots = assign_slots(
210
+ list(darray.dims),
211
+ "area",
212
+ x=x,
213
+ color=color,
214
+ pattern_shape=pattern_shape,
215
+ facet_col=facet_col,
216
+ facet_row=facet_row,
217
+ animation_frame=animation_frame,
218
+ )
219
+
220
+ df = to_dataframe(darray)
221
+ value_col = get_value_col(darray)
222
+ labels = {**build_labels(darray, slots, value_col), **px_kwargs.pop("labels", {})}
223
+
224
+ return px.area(
225
+ df,
226
+ x=slots.get("x"),
227
+ y=value_col,
228
+ color=slots.get("color"),
229
+ pattern_shape=slots.get("pattern_shape"),
230
+ facet_col=slots.get("facet_col"),
231
+ facet_row=slots.get("facet_row"),
232
+ animation_frame=slots.get("animation_frame"),
233
+ labels=labels,
234
+ **px_kwargs,
235
+ )
236
+
237
+
238
+ def box(
239
+ darray: DataArray,
240
+ *,
241
+ x: SlotValue = auto,
242
+ color: SlotValue = None,
243
+ facet_col: SlotValue = None,
244
+ facet_row: SlotValue = None,
245
+ animation_frame: SlotValue = None,
246
+ **px_kwargs: Any,
247
+ ) -> go.Figure:
248
+ """
249
+ Create an interactive box plot from a DataArray.
250
+
251
+ The y-axis shows DataArray values. By default, only x is auto-assigned;
252
+ other dimensions are aggregated into the box statistics.
253
+
254
+ Dimensions fill slots in order: x -> color -> facet_col -> facet_row -> animation_frame
255
+
256
+ Parameters
257
+ ----------
258
+ darray
259
+ The DataArray to plot.
260
+ x
261
+ Dimension for x-axis categories. Default: first dimension.
262
+ color
263
+ Dimension for color grouping. Default: None (aggregated).
264
+ facet_col
265
+ Dimension for subplot columns. Default: None (aggregated).
266
+ facet_row
267
+ Dimension for subplot rows. Default: None (aggregated).
268
+ animation_frame
269
+ Dimension for animation. Default: None (aggregated).
270
+ **px_kwargs
271
+ Additional arguments passed to `plotly.express.box()`.
272
+
273
+ Returns
274
+ -------
275
+ plotly.graph_objects.Figure
276
+ """
277
+ slots = assign_slots(
278
+ list(darray.dims),
279
+ "box",
280
+ allow_unassigned=True,
281
+ x=x,
282
+ color=color,
283
+ facet_col=facet_col,
284
+ facet_row=facet_row,
285
+ animation_frame=animation_frame,
286
+ )
287
+
288
+ df = to_dataframe(darray)
289
+ value_col = get_value_col(darray)
290
+ labels = {**build_labels(darray, slots, value_col), **px_kwargs.pop("labels", {})}
291
+
292
+ return px.box(
293
+ df,
294
+ x=slots.get("x"),
295
+ y=value_col,
296
+ color=slots.get("color"),
297
+ facet_col=slots.get("facet_col"),
298
+ facet_row=slots.get("facet_row"),
299
+ animation_frame=slots.get("animation_frame"),
300
+ labels=labels,
301
+ **px_kwargs,
302
+ )
303
+
304
+
305
+ def scatter(
306
+ darray: DataArray,
307
+ *,
308
+ x: SlotValue = auto,
309
+ y: SlotValue | str = "value",
310
+ color: SlotValue = auto,
311
+ symbol: SlotValue = auto,
312
+ facet_col: SlotValue = auto,
313
+ facet_row: SlotValue = auto,
314
+ animation_frame: SlotValue = auto,
315
+ **px_kwargs: Any,
316
+ ) -> go.Figure:
317
+ """
318
+ Create an interactive scatter plot from a DataArray.
319
+
320
+ By default, y-axis shows DataArray values. Set y to a dimension name
321
+ for dimension-vs-dimension plots (e.g., lat vs lon colored by value).
322
+
323
+ Dimensions fill slots in order:
324
+ x -> color -> symbol -> facet_col -> facet_row -> animation_frame
325
+
326
+ Parameters
327
+ ----------
328
+ darray
329
+ The DataArray to plot.
330
+ x
331
+ Dimension for x-axis. Default: first dimension.
332
+ y
333
+ What to plot on y-axis. Default "value" uses DataArray values.
334
+ Can be a dimension name for dimension vs dimension plots.
335
+ color
336
+ Dimension for color grouping. Default: second dimension.
337
+ Use "value" to color by DataArray values (useful with y=dimension).
338
+ symbol
339
+ Dimension for marker symbol. Default: third dimension.
340
+ facet_col
341
+ Dimension for subplot columns. Default: fourth dimension.
342
+ facet_row
343
+ Dimension for subplot rows. Default: fifth dimension.
344
+ animation_frame
345
+ Dimension for animation. Default: sixth dimension.
346
+ **px_kwargs
347
+ Additional arguments passed to `plotly.express.scatter()`.
348
+
349
+ Returns
350
+ -------
351
+ plotly.graph_objects.Figure
352
+ """
353
+ # If y is a dimension, exclude it from slot assignment
354
+ y_is_dim = y != "value" and y in darray.dims
355
+ dims_for_slots = [d for d in darray.dims if d != y] if y_is_dim else list(darray.dims)
356
+
357
+ slots = assign_slots(
358
+ dims_for_slots,
359
+ "scatter",
360
+ x=x,
361
+ color=color,
362
+ symbol=symbol,
363
+ facet_col=facet_col,
364
+ facet_row=facet_row,
365
+ animation_frame=animation_frame,
366
+ )
367
+
368
+ df = to_dataframe(darray)
369
+ value_col = get_value_col(darray)
370
+
371
+ # Resolve y and color columns (may be "value" -> actual column name)
372
+ y_col = value_col if y == "value" else y
373
+ color_col = value_col if slots.get("color") == "value" else slots.get("color")
374
+
375
+ # Build labels
376
+ labels = {**build_labels(darray, slots, value_col), **px_kwargs.pop("labels", {})}
377
+ if y_is_dim and str(y) not in labels:
378
+ labels[str(y)] = get_label(darray, y)
379
+
380
+ return px.scatter(
381
+ df,
382
+ x=slots.get("x"),
383
+ y=y_col,
384
+ color=color_col,
385
+ symbol=slots.get("symbol"),
386
+ facet_col=slots.get("facet_col"),
387
+ facet_row=slots.get("facet_row"),
388
+ animation_frame=slots.get("animation_frame"),
389
+ labels=labels,
390
+ **px_kwargs,
391
+ )
392
+
393
+
394
+ def imshow(
395
+ darray: DataArray,
396
+ *,
397
+ x: SlotValue = auto,
398
+ y: SlotValue = auto,
399
+ facet_col: SlotValue = auto,
400
+ animation_frame: SlotValue = auto,
401
+ **px_kwargs: Any,
402
+ ) -> go.Figure:
403
+ """
404
+ Create an interactive heatmap from a DataArray.
405
+
406
+ Both x and y are dimensions. Dimensions fill slots in order:
407
+ y (rows) -> x (columns) -> facet_col -> animation_frame
408
+
409
+ Parameters
410
+ ----------
411
+ darray
412
+ The DataArray to plot.
413
+ x
414
+ Dimension for x-axis (columns). Default: second dimension.
415
+ y
416
+ Dimension for y-axis (rows). Default: first dimension.
417
+ facet_col
418
+ Dimension for subplot columns. Default: third dimension.
419
+ animation_frame
420
+ Dimension for animation. Default: fourth dimension.
421
+ **px_kwargs
422
+ Additional arguments passed to `plotly.express.imshow()`.
423
+
424
+ Returns
425
+ -------
426
+ plotly.graph_objects.Figure
427
+ """
428
+ slots = assign_slots(
429
+ list(darray.dims),
430
+ "imshow",
431
+ y=y,
432
+ x=x,
433
+ facet_col=facet_col,
434
+ animation_frame=animation_frame,
435
+ )
436
+
437
+ # Transpose to: y (rows), x (cols), facet_col, animation_frame
438
+ transpose_order = [
439
+ slots[k] for k in ("y", "x", "facet_col", "animation_frame") if slots.get(k) is not None
440
+ ]
441
+ plot_data = darray.transpose(*transpose_order) if transpose_order else darray
442
+
443
+ return px.imshow(
444
+ plot_data,
445
+ facet_col=slots.get("facet_col"),
446
+ animation_frame=slots.get("animation_frame"),
447
+ **px_kwargs,
448
+ )
xarray_plotly/py.typed ADDED
File without changes