From f01ce2334884845b9c536333386b03fc3aac2c0f Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 16 Oct 2022 21:48:51 +0200 Subject: [PATCH 001/102] Add linecollection --- xarray/plot/dataarray_plot.py | 1 + xarray/plot/utils.py | 123 ++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 9b1630c3624..259a4fc726f 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -30,6 +30,7 @@ _ensure_plottable, _infer_interval_breaks, _infer_xy_labels, + _line, _Normalize, _process_cmap_cbar_kwargs, _rescale_imshow_rgb, diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index a19f3c54cdd..76bc59c1594 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1711,3 +1711,126 @@ def _add_legend( _adjust_legend_subtitles(legend) return legend + + +def _line( + self, + x, + y, + s=None, + c=None, + linestyle=None, + cmap=None, + norm=None, + vmin=None, + vmax=None, + alpha=None, + linewidths=None, + *, + edgecolors=None, + plotnonfinite=False, + **kwargs, +): + """ + ax.scatter-like wrapper for LineCollection. + + This function helps the handling of datetimes since Linecollection doesn't + support it directly, just like PatchCollection doesn't either. + + """ + plt = import_matplotlib_pyplot() + rcParams = plt.matplotlib.rcParams + + # Handle z inputs: + z = kwargs.pop("z", None) + if z is not None: + from mpl_toolkits.mplot3d.art3d import Line3DCollection + + LineCollection_ = Line3DCollection + add_collection_ = self.add_collection3d + auto_scale = self.auto_scale_xyz + auto_scale_args = (x, y, z, self.has_data()) + else: + LineCollection_ = plt.matplotlib.collections.LineCollection + add_collection_ = self.add_collection + auto_scale = self._request_autoscale_view + auto_scale_args = tuple() + + # Process **kwargs to handle aliases, conflicts with explicit kwargs: + x, y = self._process_unit_info([("x", x), ("y", y)], kwargs) + + if s is None: + s = np.array([rcParams["lines.linewidth"]]) + # s = np.ma.ravel(s) + if len(s) not in (1, x.size) or ( + not np.issubdtype(s.dtype, np.floating) + and not np.issubdtype(s.dtype, np.integer) + ): + raise ValueError( + "s must be a scalar, " "or float array-like with the same size as x and y" + ) + + edgecolors or kwargs.get("edgecolor", None) + c, colors, edgecolors = self._parse_scatter_color_args( + c, + edgecolors, + kwargs, + x.size, + get_next_color_func=self._get_patches_for_fill.get_next_color, + ) + + # load default linestyle from rcParams + if linestyle is None: + linestyle = rcParams["lines.linestyle"] + + drawstyle = kwargs.pop("drawstyle", "default") + if drawstyle == "default": + # Draw linear lines: + xyz = list(v for v in (x, y, z) if v is not None) + else: + # Draw stepwise lines: + from matplotlib.cbook import STEP_LOOKUP_MAP + + step_func = STEP_LOOKUP_MAP[drawstyle] + xyz = step_func(*tuple(v for v in (x, y, z) if v is not None)) + + # Create steps by repeating all elements, then roll the last array by 1: + # Might be scary duplicating number of elements? + # xyz = list(np.repeat(v, 2) for v in (x, y, z) if v is not None) + # c = np.repeat(c, 2) # TODO: Off by one? + # s = np.repeat(s, 2) + # if drawstyle == "steps-pre": + # xyz[-1][:-1] = xyz[-1][1:] + # elif drawstyle == "steps-post": + # xyz[-1][1:] = xyz[-1][:-1] + # else: + # raise NotImplementedError( + # f"Allowed values are: 'default', 'steps-pre', 'steps-post', got {drawstyle}." + # ) + + # Broadcast arrays to correct format: + # https://stackoverflow.com/questions/42215777/matplotlib-line-color-in-3d + points = np.stack(np.broadcast_arrays(*xyz), axis=-1).reshape(-1, 1, len(xyz)) + segments = np.concatenate([points[:-1], points[1:]], axis=1) + + collection = LineCollection_( + segments, + linewidths=s, + linestyles="solid", + ) + # collection.set_transform(plt.matplotlib.transforms.IdentityTransform()) + collection.update(kwargs) + + if colors is None: + collection.set_array(c) + collection.set_cmap(cmap) + collection.set_norm(norm) + collection._scale_norm(norm, vmin, vmax) + + add_collection_(collection) + + # self._request_autoscale_view() + # self.autoscale_view() + auto_scale(*auto_scale_args) + + return collection From 7025b998dff70d6ad913470d6e4469f2bc0f1fa2 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 16 Oct 2022 21:54:58 +0200 Subject: [PATCH 002/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 259a4fc726f..44e83d5d1b7 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1081,6 +1081,95 @@ def _add_labels( labels.set_ha("right") +def _line_(xplt, yplt, *args, ax, add_labels=True, **kwargs): + plt = import_matplotlib_pyplot() + + zplt = kwargs.pop("zplt", None) + hueplt = kwargs.pop("hueplt", None) + sizeplt = kwargs.pop("sizeplt", None) + + cmap = kwargs.pop("cmap", None) + vmin = kwargs.pop("vmin", None) + vmax = kwargs.pop("vmax", None) + norm = kwargs.pop("norm", None) + + c = hueplt.to_numpy() if hueplt is not None else None + s = sizeplt.to_numpy() if sizeplt is not None else None + zplt_val = zplt.to_numpy() if zplt is not None else None + + # Remove pd.Intervals if contained in xplt.values and/or yplt.values. + xplt_val, yplt_val, x_suffix, y_suffix, kwargs = _resolve_intervals_1dplot( + xplt.to_numpy(), yplt.to_numpy(), kwargs + ) + z_suffix = "" # TODO: to _resolve_intervals? + _ensure_plottable(xplt_val, yplt_val) + + if Version(plt.matplotlib.__version__) < Version("3.5.0"): + # Plot the data. 3d plots has the z value in upward direction + # instead of y. To make jumping between 2d and 3d easy and intuitive + # switch the order so that z is shown in the depthwise direction: + # axis_order = dict(x="x", y="z", z="y") + axis_order = ["x", "y", "z"] + to_plot, to_labels, to_suffix, i = {}, {}, {}, 0 + for arr, arr_val, suffix in zip( + [xplt, zplt, yplt], + [xplt_val, zplt_val, yplt_val], + (x_suffix, z_suffix, y_suffix), + ): + if arr is not None: + to_plot[axis_order[i]] = arr_val + to_labels[axis_order[i]] = arr + to_suffix[axis_order[i]] = suffix + i += 1 + # to_plot = dict(x=xplt_val, y=zplt_val, z=yplt_val) + # to_labels = dict(x=xplt, y=zplt, z=yplt) + else: + # Switching axis order not needed in 3.5.0, can also simplify the code + # that uses axis_order: + # https://github.com/matplotlib/matplotlib/pull/19873 + # axis_order = dict(x="x", y="y", z="z") + axis_order = ["x", "y", "z"] + to_plot, to_labels, to_suffix, i = {}, {}, {}, 0 + for arr, arr_val, suffix in zip( + [xplt, yplt, zplt], + [xplt_val, yplt_val, zplt_val], + (x_suffix, z_suffix, y_suffix), + ): + if arr is not None: + to_plot[axis_order[i]] = arr_val + to_labels[axis_order[i]] = arr + to_suffix[axis_order[i]] = suffix + i += 1 + + primitive = _line( + ax, + **to_plot, + s=s, + c=c, + cmap=cmap, + norm=norm, + vmin=vmin, + vmax=vmax, + **kwargs, + ) + + # Set x, y, z labels: + _add_labels( + add_labels, to_labels.values(), to_suffix.values(), (True, False, False), ax + ) + + return primitive + + +@_plot1d +def line(xplt, yplt, *args, ax, add_labels=True, **kwargs): + """ + Line plot of DataArray index against values + Wraps :func:`matplotlib:matplotlib.collections.LineCollection` + """ + return _line_(xplt, yplt, *args, ax=ax, add_labels=add_labels, **kwargs) + + @overload def scatter( darray: DataArray, From 638a91d1f4bdf91496a3b839877a16fc12651d5a Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 16 Oct 2022 22:15:04 +0200 Subject: [PATCH 003/102] add more lines --- xarray/plot/accessor.py | 8 ++++++++ xarray/plot/dataarray_plot.py | 2 +- xarray/plot/dataset_plot.py | 10 ++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/xarray/plot/accessor.py b/xarray/plot/accessor.py index 273d0f4f921..4dd973b9ba7 100644 --- a/xarray/plot/accessor.py +++ b/xarray/plot/accessor.py @@ -134,6 +134,10 @@ def line( def line(self, *args, **kwargs) -> list[Line3D] | FacetGrid[DataArray]: return dataarray_plot.line(self._da, *args, **kwargs) + @functools.wraps(dataarray_plot.lines) + def lines(self, *args, **kwargs) -> PathCollection | FacetGrid[DataArray]: + return dataarray_plot.lines(self._da, *args, **kwargs) + @overload def step( # type: ignore[misc] # None is hashable :( self, @@ -943,6 +947,10 @@ def __call__(self, *args, **kwargs) -> NoReturn: "an explicit plot method, e.g. ds.plot.scatter(...)" ) + @functools.wraps(dataset_plot.lines) + def lines(self, *args, **kwargs) -> PathCollection | FacetGrid[DataArray]: + return dataset_plot.lines(self._ds, *args, **kwargs) + @overload def scatter( self, diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 44e83d5d1b7..75def41c731 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1162,7 +1162,7 @@ def _line_(xplt, yplt, *args, ax, add_labels=True, **kwargs): @_plot1d -def line(xplt, yplt, *args, ax, add_labels=True, **kwargs): +def lines(xplt, yplt, *args, ax, add_labels=True, **kwargs): """ Line plot of DataArray index against values Wraps :func:`matplotlib:matplotlib.collections.LineCollection` diff --git a/xarray/plot/dataset_plot.py b/xarray/plot/dataset_plot.py index 55819b0ab9f..8ba5a0b81dd 100644 --- a/xarray/plot/dataset_plot.py +++ b/xarray/plot/dataset_plot.py @@ -914,3 +914,13 @@ def scatter( da = _temp_dataarray(ds, y, locals_) return da.plot.scatter(*locals_.pop("args", ()), **locals_) + + +@_update_doc_to_dataset(dataarray_plot.lines) +def lines(ds, x, y, *args, **kwargs): + """Line plot Dataset data variables against each other.""" + kwargs.update(x=x) + locals_ = _normalize_args("lines", args, kwargs) + da = _temp_dataarray(ds, y, locals_) + + return da.plot.lines(*locals_.pop("args", ()), **locals_) From cf0d4aeb6794845faf16554dfcc0c0d3c329c33d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 18 Oct 2022 20:01:41 +0200 Subject: [PATCH 004/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 074b4eb9344..580248d0c43 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1015,7 +1015,7 @@ def newplotfunc( ) if add_legend_: - if plotfunc.__name__ in ["scatter", "line"]: + if plotfunc.__name__ in ["scatter", "lines"]: _add_legend( hueplt_norm if add_legend or not add_colorbar_ From 83601751cc430b2a02a4f97e93b946e8260c3221 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 21 May 2023 15:12:28 +0200 Subject: [PATCH 005/102] Remove old code --- xarray/plot/dataarray_plot.py | 194 +++++++++++++++++++++++++++------- 1 file changed, 154 insertions(+), 40 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index affa262fe58..98af22978da 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -36,7 +36,7 @@ if TYPE_CHECKING: from matplotlib.axes import Axes - from matplotlib.collections import PathCollection, QuadMesh + from matplotlib.collections import LineCollection, PathCollection, QuadMesh from matplotlib.colors import Colormap, Normalize from matplotlib.container import BarContainer from matplotlib.contour import QuadContourSet @@ -1103,7 +1103,13 @@ def _add_labels( labels.set_horizontalalignment("right") -def _line_(xplt, yplt, *args, ax, add_labels=True, **kwargs): +def _line_( + xplt: DataArray | None, + yplt: DataArray | None, + ax: Axes, + add_labels: bool | Iterable[bool] = True, + **kwargs, +) -> LineCollection: plt = import_matplotlib_pyplot() zplt = kwargs.pop("zplt", None) @@ -1126,42 +1132,18 @@ def _line_(xplt, yplt, *args, ax, add_labels=True, **kwargs): z_suffix = "" # TODO: to _resolve_intervals? _ensure_plottable(xplt_val, yplt_val) - if Version(plt.matplotlib.__version__) < Version("3.5.0"): - # Plot the data. 3d plots has the z value in upward direction - # instead of y. To make jumping between 2d and 3d easy and intuitive - # switch the order so that z is shown in the depthwise direction: - # axis_order = dict(x="x", y="z", z="y") - axis_order = ["x", "y", "z"] - to_plot, to_labels, to_suffix, i = {}, {}, {}, 0 - for arr, arr_val, suffix in zip( - [xplt, zplt, yplt], - [xplt_val, zplt_val, yplt_val], - (x_suffix, z_suffix, y_suffix), - ): - if arr is not None: - to_plot[axis_order[i]] = arr_val - to_labels[axis_order[i]] = arr - to_suffix[axis_order[i]] = suffix - i += 1 - # to_plot = dict(x=xplt_val, y=zplt_val, z=yplt_val) - # to_labels = dict(x=xplt, y=zplt, z=yplt) - else: - # Switching axis order not needed in 3.5.0, can also simplify the code - # that uses axis_order: - # https://github.com/matplotlib/matplotlib/pull/19873 - # axis_order = dict(x="x", y="y", z="z") - axis_order = ["x", "y", "z"] - to_plot, to_labels, to_suffix, i = {}, {}, {}, 0 - for arr, arr_val, suffix in zip( - [xplt, yplt, zplt], - [xplt_val, yplt_val, zplt_val], - (x_suffix, z_suffix, y_suffix), - ): - if arr is not None: - to_plot[axis_order[i]] = arr_val - to_labels[axis_order[i]] = arr - to_suffix[axis_order[i]] = suffix - i += 1 + axis_order = ["x", "y", "z"] + to_plot, to_labels, to_suffix, i = {}, {}, {}, 0 + for arr, arr_val, suffix in zip( + [xplt, yplt, zplt], + [xplt_val, yplt_val, zplt_val], + (x_suffix, z_suffix, y_suffix), + ): + if arr is not None: + to_plot[axis_order[i]] = arr_val + to_labels[axis_order[i]] = arr + to_suffix[axis_order[i]] = suffix + i += 1 primitive = _line( ax, @@ -1183,13 +1165,145 @@ def _line_(xplt, yplt, *args, ax, add_labels=True, **kwargs): return primitive +@overload +def lines( + darray: DataArray, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: None = None, # no wrap -> primitive + col: None = None, # no wrap -> primitive + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs, +) -> LineCollection: + ... + + +@overload +def lines( + darray: DataArray, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable | None = None, + col: Hashable, # wrap -> FacetGrid + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs, +) -> FacetGrid[DataArray]: + ... + + +@overload +def lines( + darray: DataArray, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable, # wrap -> FacetGrid + col: Hashable | None = None, + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs, +) -> FacetGrid[DataArray]: + ... + + @_plot1d -def lines(xplt, yplt, *args, ax, add_labels=True, **kwargs): +def lines( + xplt: DataArray | None, + yplt: DataArray | None, + ax: Axes, + add_labels: bool | Iterable[bool] = True, + **kwargs, +) -> LineCollection: """ Line plot of DataArray index against values Wraps :func:`matplotlib:matplotlib.collections.LineCollection` """ - return _line_(xplt, yplt, *args, ax=ax, add_labels=add_labels, **kwargs) + return _line_(xplt, yplt, ax=ax, add_labels=add_labels, **kwargs) @overload From 7a0a7391093d762f0fa54a90808d80c533b39edb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 21 May 2023 13:13:07 +0000 Subject: [PATCH 006/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/dataarray_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 98af22978da..fc73569884b 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1110,7 +1110,7 @@ def _line_( add_labels: bool | Iterable[bool] = True, **kwargs, ) -> LineCollection: - plt = import_matplotlib_pyplot() + import_matplotlib_pyplot() zplt = kwargs.pop("zplt", None) hueplt = kwargs.pop("hueplt", None) From d51bf709dc51ff12d6945d8638a20f54ea381fd9 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 21 May 2023 15:18:41 +0200 Subject: [PATCH 007/102] Update accessor.py --- xarray/plot/accessor.py | 127 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/xarray/plot/accessor.py b/xarray/plot/accessor.py index 33cb69b1c7a..e65fb38263c 100644 --- a/xarray/plot/accessor.py +++ b/xarray/plot/accessor.py @@ -136,7 +136,7 @@ def line(self, *args, **kwargs) -> list[Line3D] | FacetGrid[DataArray]: return dataarray_plot.line(self._da, *args, **kwargs) @functools.wraps(dataarray_plot.lines) - def lines(self, *args, **kwargs) -> PathCollection | FacetGrid[DataArray]: + def lines(self, *args, **kwargs) -> LineCollection | FacetGrid[DataArray]: return dataarray_plot.lines(self._da, *args, **kwargs) @overload @@ -948,8 +948,131 @@ def __call__(self, *args, **kwargs) -> NoReturn: "an explicit plot method, e.g. ds.plot.scatter(...)" ) + @overload + def lines( + self, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: None = None, # no wrap -> primitive + col: None = None, # no wrap -> primitive + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap=None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend=None, + levels=None, + **kwargs: Any, + ) -> LineCollection: + ... + + @overload + def lines( + self, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable | None = None, + col: Hashable, # wrap -> FacetGrid + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap=None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend=None, + levels=None, + **kwargs: Any, + ) -> FacetGrid[DataArray]: + ... + + @overload + def lines( + self, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable, # wrap -> FacetGrid + col: Hashable | None = None, + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap=None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend=None, + levels=None, + **kwargs: Any, + ) -> FacetGrid[DataArray]: + ... + @functools.wraps(dataset_plot.lines) - def lines(self, *args, **kwargs) -> PathCollection | FacetGrid[DataArray]: + def lines(self, *args, **kwargs) -> LineCollection | FacetGrid[DataArray]: return dataset_plot.lines(self._ds, *args, **kwargs) @overload From 93a132cebe68163ae508741a8926451632ec0c7f Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 21 May 2023 16:03:42 +0200 Subject: [PATCH 008/102] keep similar format as scatter --- xarray/plot/dataarray_plot.py | 93 +++++++++++------------------------ 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index fc73569884b..c10d3e2566f 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1103,68 +1103,6 @@ def _add_labels( labels.set_horizontalalignment("right") -def _line_( - xplt: DataArray | None, - yplt: DataArray | None, - ax: Axes, - add_labels: bool | Iterable[bool] = True, - **kwargs, -) -> LineCollection: - import_matplotlib_pyplot() - - zplt = kwargs.pop("zplt", None) - hueplt = kwargs.pop("hueplt", None) - sizeplt = kwargs.pop("sizeplt", None) - - cmap = kwargs.pop("cmap", None) - vmin = kwargs.pop("vmin", None) - vmax = kwargs.pop("vmax", None) - norm = kwargs.pop("norm", None) - - c = hueplt.to_numpy() if hueplt is not None else None - s = sizeplt.to_numpy() if sizeplt is not None else None - zplt_val = zplt.to_numpy() if zplt is not None else None - - # Remove pd.Intervals if contained in xplt.values and/or yplt.values. - xplt_val, yplt_val, x_suffix, y_suffix, kwargs = _resolve_intervals_1dplot( - xplt.to_numpy(), yplt.to_numpy(), kwargs - ) - z_suffix = "" # TODO: to _resolve_intervals? - _ensure_plottable(xplt_val, yplt_val) - - axis_order = ["x", "y", "z"] - to_plot, to_labels, to_suffix, i = {}, {}, {}, 0 - for arr, arr_val, suffix in zip( - [xplt, yplt, zplt], - [xplt_val, yplt_val, zplt_val], - (x_suffix, z_suffix, y_suffix), - ): - if arr is not None: - to_plot[axis_order[i]] = arr_val - to_labels[axis_order[i]] = arr - to_suffix[axis_order[i]] = suffix - i += 1 - - primitive = _line( - ax, - **to_plot, - s=s, - c=c, - cmap=cmap, - norm=norm, - vmin=vmin, - vmax=vmax, - **kwargs, - ) - - # Set x, y, z labels: - _add_labels( - add_labels, to_labels.values(), to_suffix.values(), (True, False, False), ax - ) - - return primitive - - @overload def lines( darray: DataArray, @@ -1303,7 +1241,36 @@ def lines( Line plot of DataArray index against values Wraps :func:`matplotlib:matplotlib.collections.LineCollection` """ - return _line_(xplt, yplt, ax=ax, add_labels=add_labels, **kwargs) + if "u" in kwargs or "v" in kwargs: + raise ValueError("u, v are not allowed in scatter plots.") + + zplt: DataArray | None = kwargs.pop("zplt", None) + hueplt: DataArray | None = kwargs.pop("hueplt", None) + sizeplt: DataArray | None = kwargs.pop("sizeplt", None) + + if hueplt is not None: + kwargs.update(c=hueplt.to_numpy().ravel()) + + if sizeplt is not None: + kwargs.update(s=sizeplt.to_numpy().ravel()) + + # # Remove pd.Intervals if contained in xplt.values and/or yplt.values. + # xplt_val, yplt_val, x_suffix, y_suffix, kwargs = _resolve_intervals_1dplot( + # xplt.to_numpy(), yplt.to_numpy(), kwargs + # ) + # zplt_val = zplt.to_numpy() if zplt is not None else None + # z_suffix = "" # TODO: to _resolve_intervals? + # _ensure_plottable(xplt_val, yplt_val) + + axis_order = ["x", "y", "z"] + + plts_dict: dict[str, DataArray | None] = dict(x=xplt, y=yplt, z=zplt) + plts_or_none = [plts_dict[v] for v in axis_order] + plts = [p for p in plts_or_none if p is not None] + primitive = ax.scatter(*[p.to_numpy().ravel() for p in plts], **kwargs) + _add_labels(add_labels, plts, ("", "", ""), (True, False, False), ax) + + return primitive @overload From ce4a8060c2ab6aebdf2a1be3efe85d3fb3fdc39f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 21 May 2023 14:04:45 +0000 Subject: [PATCH 009/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/dataarray_plot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index c10d3e2566f..7c3574f7916 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -22,7 +22,6 @@ _guess_coords_to_plot, _infer_interval_breaks, _infer_xy_labels, - _line, _Normalize, _process_cmap_cbar_kwargs, _rescale_imshow_rgb, From 2bd5aac1526379cdc22ac34de27ff6806862f8d2 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 21 May 2023 16:08:59 +0200 Subject: [PATCH 010/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 7c3574f7916..59d896e9d4c 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -22,6 +22,7 @@ _guess_coords_to_plot, _infer_interval_breaks, _infer_xy_labels, + _line, _Normalize, _process_cmap_cbar_kwargs, _rescale_imshow_rgb, @@ -1266,7 +1267,7 @@ def lines( plts_dict: dict[str, DataArray | None] = dict(x=xplt, y=yplt, z=zplt) plts_or_none = [plts_dict[v] for v in axis_order] plts = [p for p in plts_or_none if p is not None] - primitive = ax.scatter(*[p.to_numpy().ravel() for p in plts], **kwargs) + primitive = _line(*[p.to_numpy().ravel() for p in plts], **kwargs) _add_labels(add_labels, plts, ("", "", ""), (True, False, False), ax) return primitive From dfc3bb8c1c862ebf56d0d4843a68f73921566a0d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 21 May 2023 16:24:28 +0200 Subject: [PATCH 011/102] keep same format as scatter --- xarray/plot/dataset_plot.py | 170 +++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 3 deletions(-) diff --git a/xarray/plot/dataset_plot.py b/xarray/plot/dataset_plot.py index 493bcd4bba2..a20ddb29662 100644 --- a/xarray/plot/dataset_plot.py +++ b/xarray/plot/dataset_plot.py @@ -921,11 +921,175 @@ def scatter( return da.plot.scatter(*locals_.pop("args", ()), **locals_) +@overload +def lines( + ds: Dataset, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: None = None, # no wrap -> primitive + col: None = None, # no wrap -> primitive + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs: Any, +) -> LineCollection: + ... + + +@overload +def lines( + ds: Dataset, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable | None = None, + col: Hashable, # wrap -> FacetGrid + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs: Any, +) -> FacetGrid[DataArray]: + ... + + +@overload +def lines( + ds: Dataset, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable, # wrap -> FacetGrid + col: Hashable | None = None, + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs: Any, +) -> FacetGrid[DataArray]: + ... + + @_update_doc_to_dataset(dataarray_plot.lines) -def lines(ds, x, y, *args, **kwargs): +def lines( + ds: Dataset, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable | None = None, + col: Hashable | None = None, + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, + **kwargs: Any, +) -> LineCollection | FacetGrid[DataArray]: """Line plot Dataset data variables against each other.""" - kwargs.update(x=x) - locals_ = _normalize_args("lines", args, kwargs) + locals_ = locals() + del locals_["ds"] + locals_.update(locals_.pop("kwargs", {})) da = _temp_dataarray(ds, y, locals_) return da.plot.lines(*locals_.pop("args", ()), **locals_) From 2e940c3d9636f08a1b1d9e037c3fd641bdb8b786 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:41:01 +0200 Subject: [PATCH 012/102] Fix lines plot --- xarray/plot/dataarray_plot.py | 3 +- xarray/plot/utils.py | 88 ++++++++++++++++++++++++++++------- xarray/tests/test_plot.py | 40 ++++++++++++++++ 3 files changed, 113 insertions(+), 18 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index e8367d4cb72..9b747b0f51e 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -200,6 +200,7 @@ def _prepare_plot1d_data( # Lines should never connect to the same coordinate when stacked, # transpose to avoid this as much as possible: + print("to_transpose", dims_T) darray = darray.transpose(..., *dims_T) # Array is now ready to be stacked: @@ -1271,7 +1272,7 @@ def lines( plts_dict: dict[str, DataArray | None] = dict(x=xplt, y=yplt, z=zplt) plts_or_none = [plts_dict[v] for v in axis_order] plts = [p for p in plts_or_none if p is not None] - primitive = _line(*[p.to_numpy().ravel() for p in plts], **kwargs) + primitive = _line(ax, *[p.to_numpy().ravel() for p in plts], **kwargs) _add_labels(add_labels, plts, ("", "", ""), (True, False, False), ax) return primitive diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index ec94c3ad84a..9316b2ab964 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -6,7 +6,7 @@ from collections.abc import Hashable, Iterable, Mapping, MutableMapping, Sequence from datetime import datetime from inspect import getfullargspec -from typing import TYPE_CHECKING, Any, Callable, overload +from typing import TYPE_CHECKING, Any, Callable, Literal, overload import numpy as np import pandas as pd @@ -27,8 +27,13 @@ if TYPE_CHECKING: from matplotlib.axes import Axes - from matplotlib.colors import Normalize + from matplotlib.collections import LineCollection + from matplotlib.colors import Colormap, Normalize from matplotlib.ticker import FuncFormatter + from matplotlib.typing import ColorType, LineStyleType + + from mpl_toolkits.mplot3d.art3d import Line3DCollection + from numpy.typing import ArrayLike from xarray.core.dataarray import DataArray @@ -1836,24 +1841,74 @@ def _guess_coords_to_plot( return coords_to_plot +@overload def _line( self, - x, - y, - s=None, - c=None, - linestyle=None, - cmap=None, - norm=None, - vmin=None, - vmax=None, - alpha=None, - linewidths=None, + x: float | ArrayLike, + y: float | ArrayLike, + z: None = None, + s: float | ArrayLike | None = None, + c: Sequence[ColorType] | ColorType | None = None, + linestyle: LineStyleType | None = None, + cmap: str | Colormap | None = None, + norm: str | Normalize | None = None, + vmin: float | None = None, + vmax: float | None = None, + alpha: float | None = None, + linewidths: float | Sequence[float] | None = None, *, - edgecolors=None, - plotnonfinite=False, + edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, + plotnonfinite: bool = False, + data=None, **kwargs, -): +) -> LineCollection: + ... + + +@overload +def _line( + self, + x: float | ArrayLike, + y: float | ArrayLike, + z: float | ArrayLike = None, + s: float | ArrayLike | None = None, + c: Sequence[ColorType] | ColorType | None = None, + linestyle: LineStyleType | None = None, + cmap: str | Colormap | None = None, + norm: str | Normalize | None = None, + vmin: float | None = None, + vmax: float | None = None, + alpha: float | None = None, + linewidths: float | Sequence[float] | None = None, + *, + edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, + plotnonfinite: bool = False, + data=None, + **kwargs, +) -> Line3DCollection: + ... + + +def _line( + self, + x: float | ArrayLike, + y: float | ArrayLike, + z: float | ArrayLike | None = None, + s: float | ArrayLike | None = None, + c: Sequence[ColorType] | ColorType | None = None, + linestyle: LineStyleType | None = None, + cmap: str | Colormap | None = None, + norm: str | Normalize | None = None, + vmin: float | None = None, + vmax: float | None = None, + alpha: float | None = None, + linewidths: float | Sequence[float] | None = None, + *, + edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, + plotnonfinite: bool = False, + data=None, + **kwargs, +) -> LineCollection | Line3DCollection: """ ax.scatter-like wrapper for LineCollection. @@ -1865,7 +1920,6 @@ def _line( rcParams = plt.matplotlib.rcParams # Handle z inputs: - z = kwargs.pop("z", None) if z is not None: from mpl_toolkits.mplot3d.art3d import Line3DCollection diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 8b2dfbdec41..c2a06aadb5e 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3269,3 +3269,43 @@ def test_plot1d_default_rcparams() -> None: np.testing.assert_allclose( ax.collections[0].get_edgecolor(), mpl.colors.to_rgba_array("k") ) + + +@requires_matplotlib +@pytest.mark.parametrize( + "x, y, z, hue, markersize, row, col, add_legend, add_colorbar", + [ + ("A", "B", None, None, None, None, None, None, None), + ("B", "A", None, "w", None, None, None, True, None), + ("A", "B", None, "y", "x", None, None, True, True), + ("A", "B", "z", None, None, None, None, None, None), + ("B", "A", "z", "w", None, None, None, True, None), + ("A", "B", "z", "y", "x", None, None, True, True), + ("A", "B", "z", "y", "x", "w", None, True, True), + ], +) +def test_dataarray_lines( + x, y, z, hue, markersize, row, col, add_legend, add_colorbar +) -> None: + """Test datarray lines.""" + ds = xr.tutorial.scatter_example_dataset() + + extra_coords = [v for v in [x, hue, markersize] if v is not None] + + # Base coords: + coords = dict(ds.coords) + + # Add extra coords to the DataArray: + coords.update({v: ds[v] for v in extra_coords}) + + darray = xr.DataArray(ds[y], coords=coords) + + with figure_context(): + darray.plot.lines( + x=x, + z=z, + hue=hue, + markersize=markersize, + add_legend=add_legend, + add_colorbar=add_colorbar, + ) From 7c102d57509919ee88832484deac93bc241c1a3a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:41:46 +0000 Subject: [PATCH 013/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 9316b2ab964..6031eca9078 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -31,9 +31,7 @@ from matplotlib.colors import Colormap, Normalize from matplotlib.ticker import FuncFormatter from matplotlib.typing import ColorType, LineStyleType - from mpl_toolkits.mplot3d.art3d import Line3DCollection - from numpy.typing import ArrayLike from xarray.core.dataarray import DataArray From 789d6af590dbccdfc1f4f7634809a6850cbfca83 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:46:23 +0200 Subject: [PATCH 014/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 9b747b0f51e..b71c60566f5 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -200,7 +200,6 @@ def _prepare_plot1d_data( # Lines should never connect to the same coordinate when stacked, # transpose to avoid this as much as possible: - print("to_transpose", dims_T) darray = darray.transpose(..., *dims_T) # Array is now ready to be stacked: From 0cb969a27cc5d2a6863dbfeb927bbaa989724fe5 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 17 Sep 2023 20:40:13 +0200 Subject: [PATCH 015/102] Update utils.py --- xarray/plot/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 9b9327c7ddd..fba6608b436 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1907,7 +1907,8 @@ def _line( support it directly, just like PatchCollection doesn't either. """ - plt = import_matplotlib_pyplot() + import matplotlib.pyplot as plt + rcParams = plt.matplotlib.rcParams # Handle z inputs: From d8204e6402d8cce56ca7cd2a66ab9e89f1521711 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 17 Sep 2023 20:41:20 +0200 Subject: [PATCH 016/102] Attempt at hanlding coordinates with multiple dimensions --- xarray/plot/dataarray_plot.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 2b65a91966c..b418c1e219c 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -185,18 +185,32 @@ def _prepare_plot1d_data( """ # If there are more than 1 dimension in the array than stack all the # dimensions so the plotter can plot anything: - if darray.ndim > 1: + if darray.ndim >= 2: # When stacking dims the lines will continue connecting. For floats # this can be solved by adding a nan element in between the flattening # points: dims_T = [] if np.issubdtype(darray.dtype, np.floating): - for v in ["z", "x"]: - dim = coords_to_plot.get(v, None) - if (dim is not None) and (dim in darray.dims): - darray_nan = np.nan * darray.isel({dim: -1}) - darray = concat([darray, darray_nan], dim=dim) - dims_T.append(coords_to_plot[v]) + i = 0 + for v in ("z", "x"): + coord = coords_to_plot.get(v, None) + if coord is not None: + if coord in darray.dims: + # Dimension coordinate: + d = coord + else: + # Coordinate with multiple dimensions: + c = darray[coord] + dims_filt = dict.fromkeys(c.dims) + for k in dims_filt.keys() & set(dims_T): + dims_filt.pop(k) + + d = tuple(dims_filt.keys())[i] + + darray_nan = np.nan * darray.isel({d: -1}) + darray = concat([darray, darray_nan], dim=d) + dims_T.append(d) + i += 1 # Lines should never connect to the same coordinate when stacked, # transpose to avoid this as much as possible: From 4a1e2d6c92e46543c1f9429c43249152590765ed Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Dec 2023 23:10:26 +0000 Subject: [PATCH 017/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index d7fd4b1599e..a832f6d6d01 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -2003,6 +2003,8 @@ def _line( auto_scale(*auto_scale_args) return collection + + def _set_concise_date(ax: Axes, axis: Literal["x", "y", "z"] = "x") -> None: """ Use ConciseDateFormatter which is meant to improve the From baf93abe2239328c6439e277cf89047ae9f07feb Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:05:25 +0100 Subject: [PATCH 018/102] Update test_plot.py --- xarray/tests/test_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index ccfcf599065..43050453e94 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3423,4 +3423,4 @@ def test_dataarray_lines( markersize=markersize, add_legend=add_legend, add_colorbar=add_colorbar, - ) \ No newline at end of file + ) From d5467a61e9b7e61f552ff7124de2978ebb3d0b69 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 11:06:05 +0000 Subject: [PATCH 019/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/accessor.py | 9 +++------ xarray/plot/dataarray_plot.py | 9 +++------ xarray/plot/dataset_plot.py | 9 +++------ xarray/plot/utils.py | 6 ++---- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/xarray/plot/accessor.py b/xarray/plot/accessor.py index 8142c1acf21..9df4b22554a 100644 --- a/xarray/plot/accessor.py +++ b/xarray/plot/accessor.py @@ -965,8 +965,7 @@ def lines( extend=None, levels=None, **kwargs: Any, - ) -> LineCollection: - ... + ) -> LineCollection: ... @overload def lines( @@ -1006,8 +1005,7 @@ def lines( extend=None, levels=None, **kwargs: Any, - ) -> FacetGrid[DataArray]: - ... + ) -> FacetGrid[DataArray]: ... @overload def lines( @@ -1047,8 +1045,7 @@ def lines( extend=None, levels=None, **kwargs: Any, - ) -> FacetGrid[DataArray]: - ... + ) -> FacetGrid[DataArray]: ... @functools.wraps(dataset_plot.lines) def lines(self, *args, **kwargs) -> LineCollection | FacetGrid[DataArray]: diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index ac888f90252..39793cdc83b 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1155,8 +1155,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1197,8 +1196,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @overload @@ -1239,8 +1237,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @_plot1d diff --git a/xarray/plot/dataset_plot.py b/xarray/plot/dataset_plot.py index e9ce56a8abb..d933f51f13e 100644 --- a/xarray/plot/dataset_plot.py +++ b/xarray/plot/dataset_plot.py @@ -951,8 +951,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs: Any, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -993,8 +992,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs: Any, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @overload @@ -1035,8 +1033,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs: Any, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @_update_doc_to_dataset(dataarray_plot.lines) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 058fbd92aa1..6cec0cf06e2 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1846,8 +1846,7 @@ def _line( plotnonfinite: bool = False, data=None, **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1870,8 +1869,7 @@ def _line( plotnonfinite: bool = False, data=None, **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From 6044e783b36f559aece712b63ac773f3d9046195 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:08:38 +0100 Subject: [PATCH 020/102] Update test_plot.py --- xarray/tests/test_plot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 43050453e94..c62cee46fc4 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3374,6 +3374,7 @@ def test_plot1d_default_rcparams() -> None: ) +@requires_matplotlib def test_plot1d_filtered_nulls() -> None: ds = xr.tutorial.scatter_example_dataset(seed=42) y = ds.y.where(ds.y > 0.2) From d9d0db433ee33fbade2960421774bbb264b5c05e Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:51:43 +0100 Subject: [PATCH 021/102] merge tests --- xarray/tests/test_plot.py | 58 ++++++++++----------------------------- 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index c62cee46fc4..3622a4f4eaf 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3244,6 +3244,7 @@ def test_maybe_gca() -> None: @requires_matplotlib +@pytest.mark.parametrize("plotfunc", ["scatter", "lines"]) @pytest.mark.parametrize( "x, y, z, hue, markersize, row, col, add_legend, add_colorbar", [ @@ -3256,10 +3257,19 @@ def test_maybe_gca() -> None: ("A", "B", "z", "y", "x", "w", None, True, True), ], ) -def test_datarray_scatter( - x, y, z, hue, markersize, row, col, add_legend, add_colorbar +def test_plot1d_functions( + x: Hashable, + y: Hashable, + z: Hashable, + hue: Hashable, + markersize: Hashable, + row: Hashable, + col: Hashable, + add_legend: bool | None, + add_colorbar: bool | None, + plotfunc: str, ) -> None: - """Test datarray scatter. Merge with TestPlot1D eventually.""" + """Test plot1d function. Merge with TestPlot1D eventually.""" ds = xr.tutorial.scatter_example_dataset() extra_coords = [v for v in [x, hue, markersize] if v is not None] @@ -3273,7 +3283,7 @@ def test_datarray_scatter( darray = xr.DataArray(ds[y], coords=coords) with figure_context(): - darray.plot.scatter( + getattr(darray.plot, plotfunc)( x=x, z=z, hue=hue, @@ -3385,43 +3395,3 @@ def test_plot1d_filtered_nulls() -> None: actual = pc.get_offsets().shape[0] assert expected == actual - - -@requires_matplotlib -@pytest.mark.parametrize( - "x, y, z, hue, markersize, row, col, add_legend, add_colorbar", - [ - ("A", "B", None, None, None, None, None, None, None), - ("B", "A", None, "w", None, None, None, True, None), - ("A", "B", None, "y", "x", None, None, True, True), - ("A", "B", "z", None, None, None, None, None, None), - ("B", "A", "z", "w", None, None, None, True, None), - ("A", "B", "z", "y", "x", None, None, True, True), - ("A", "B", "z", "y", "x", "w", None, True, True), - ], -) -def test_dataarray_lines( - x, y, z, hue, markersize, row, col, add_legend, add_colorbar -) -> None: - """Test datarray lines.""" - ds = xr.tutorial.scatter_example_dataset() - - extra_coords = [v for v in [x, hue, markersize] if v is not None] - - # Base coords: - coords = dict(ds.coords) - - # Add extra coords to the DataArray: - coords.update({v: ds[v] for v in extra_coords}) - - darray = xr.DataArray(ds[y], coords=coords) - - with figure_context(): - darray.plot.lines( - x=x, - z=z, - hue=hue, - markersize=markersize, - add_legend=add_legend, - add_colorbar=add_colorbar, - ) From 0bac33aded9e1ac4462e378e263819430e46797f Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:52:13 +0100 Subject: [PATCH 022/102] Use similar format as scatter --- xarray/plot/dataarray_plot.py | 145 ++++++++++++++++++++++++---------- 1 file changed, 103 insertions(+), 42 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 39793cdc83b..cfd46498c6f 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -348,7 +348,8 @@ def line( # type: ignore[misc,unused-ignore] # None is hashable :( add_legend: bool = True, _labels: bool = True, **kwargs: Any, -) -> list[Line3D]: ... +) -> list[Line3D]: + ... @overload @@ -375,7 +376,8 @@ def line( add_legend: bool = True, _labels: bool = True, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -402,7 +404,8 @@ def line( add_legend: bool = True, _labels: bool = True, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... # This function signature should not change so that it can use @@ -556,7 +559,8 @@ def step( # type: ignore[misc,unused-ignore] # None is hashable :( row: None = None, # no wrap -> primitive col: None = None, # no wrap -> primitive **kwargs: Any, -) -> list[Line3D]: ... +) -> list[Line3D]: + ... @overload @@ -569,7 +573,8 @@ def step( row: Hashable, # wrap -> FacetGrid col: Hashable | None = None, **kwargs: Any, -) -> FacetGrid[DataArray]: ... +) -> FacetGrid[DataArray]: + ... @overload @@ -582,7 +587,8 @@ def step( row: Hashable | None = None, col: Hashable, # wrap -> FacetGrid **kwargs: Any, -) -> FacetGrid[DataArray]: ... +) -> FacetGrid[DataArray]: + ... def step( @@ -1155,7 +1161,8 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1196,7 +1203,8 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[DataArray]: ... +) -> FacetGrid[DataArray]: + ... @overload @@ -1237,7 +1245,8 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[DataArray]: ... +) -> FacetGrid[DataArray]: + ... @_plot1d @@ -1252,8 +1261,39 @@ def lines( Line plot of DataArray index against values Wraps :func:`matplotlib:matplotlib.collections.LineCollection` """ + # if "u" in kwargs or "v" in kwargs: + # raise ValueError("u, v are not allowed in scatter plots.") + + # zplt: DataArray | None = kwargs.pop("zplt", None) + # hueplt: DataArray | None = kwargs.pop("hueplt", None) + # sizeplt: DataArray | None = kwargs.pop("sizeplt", None) + + # if hueplt is not None: + # kwargs.update(c=hueplt.to_numpy().ravel()) + + # if sizeplt is not None: + # kwargs.update(s=sizeplt.to_numpy().ravel()) + + # # # Remove pd.Intervals if contained in xplt.values and/or yplt.values. + # # xplt_val, yplt_val, x_suffix, y_suffix, kwargs = _resolve_intervals_1dplot( + # # xplt.to_numpy(), yplt.to_numpy(), kwargs + # # ) + # # zplt_val = zplt.to_numpy() if zplt is not None else None + # # z_suffix = "" # TODO: to _resolve_intervals? + # # _ensure_plottable(xplt_val, yplt_val) + + # axis_order = ["x", "y", "z"] + + # plts_dict: dict[str, DataArray | None] = dict(x=xplt, y=yplt, z=zplt) + # plts_or_none = [plts_dict[v] for v in axis_order] + # plts = [p for p in plts_or_none if p is not None] + # primitive = _line(ax, *[p.to_numpy().ravel() for p in plts], **kwargs) + # _add_labels(add_labels, plts, ("", "", ""), (True, False, False), ax) + + # return primitive + if "u" in kwargs or "v" in kwargs: - raise ValueError("u, v are not allowed in scatter plots.") + raise ValueError("u, v are not allowed in lines plots.") zplt: DataArray | None = kwargs.pop("zplt", None) hueplt: DataArray | None = kwargs.pop("hueplt", None) @@ -1265,23 +1305,26 @@ def lines( if sizeplt is not None: kwargs.update(s=sizeplt.to_numpy().ravel()) - # # Remove pd.Intervals if contained in xplt.values and/or yplt.values. - # xplt_val, yplt_val, x_suffix, y_suffix, kwargs = _resolve_intervals_1dplot( - # xplt.to_numpy(), yplt.to_numpy(), kwargs - # ) - # zplt_val = zplt.to_numpy() if zplt is not None else None - # z_suffix = "" # TODO: to _resolve_intervals? - # _ensure_plottable(xplt_val, yplt_val) + plts_or_none = (xplt, yplt, zplt) + _add_labels(add_labels, plts_or_none, ("", "", ""), ax) - axis_order = ["x", "y", "z"] + xplt_np = None if xplt is None else xplt.to_numpy().ravel() + yplt_np = None if yplt is None else yplt.to_numpy().ravel() + zplt_np = None if zplt is None else zplt.to_numpy().ravel() + plts_np = tuple(p for p in (xplt_np, yplt_np, zplt_np) if p is not None) - plts_dict: dict[str, DataArray | None] = dict(x=xplt, y=yplt, z=zplt) - plts_or_none = [plts_dict[v] for v in axis_order] - plts = [p for p in plts_or_none if p is not None] - primitive = _line(ax, *[p.to_numpy().ravel() for p in plts], **kwargs) - _add_labels(add_labels, plts, ("", "", ""), (True, False, False), ax) + if len(plts_np) == 3: + import mpl_toolkits - return primitive + assert isinstance(ax, mpl_toolkits.mplot3d.axes3d.Axes3D) + # return ax.scatter(xplt_np, yplt_np, zplt_np, **kwargs) + return _line(ax, xplt_np, yplt_np, zplt_np, **kwargs) + + if len(plts_np) == 2: + # return ax.scatter(plts_np[0], plts_np[1], **kwargs) + return _line(ax, plts_np[0], plts_np[1], **kwargs) + + raise ValueError("At least two variables required for a lines plot.") @overload @@ -1322,7 +1365,8 @@ def scatter( # type: ignore[misc,unused-ignore] # None is hashable :( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> PathCollection: ... +) -> PathCollection: + ... @overload @@ -1363,7 +1407,8 @@ def scatter( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -1404,7 +1449,8 @@ def scatter( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @_plot1d @@ -1871,7 +1917,8 @@ def imshow( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> AxesImage: ... +) -> AxesImage: + ... @overload @@ -1911,7 +1958,8 @@ def imshow( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -1951,7 +1999,8 @@ def imshow( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @_plot2d @@ -2087,7 +2136,8 @@ def contour( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> QuadContourSet: ... +) -> QuadContourSet: + ... @overload @@ -2127,7 +2177,8 @@ def contour( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -2167,7 +2218,8 @@ def contour( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @_plot2d @@ -2220,7 +2272,8 @@ def contourf( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> QuadContourSet: ... +) -> QuadContourSet: + ... @overload @@ -2260,7 +2313,8 @@ def contourf( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -2300,7 +2354,8 @@ def contourf( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @_plot2d @@ -2353,7 +2408,8 @@ def pcolormesh( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> QuadMesh: ... +) -> QuadMesh: + ... @overload @@ -2393,7 +2449,8 @@ def pcolormesh( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -2433,7 +2490,8 @@ def pcolormesh( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @_plot2d @@ -2537,7 +2595,8 @@ def surface( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> Poly3DCollection: ... +) -> Poly3DCollection: + ... @overload @@ -2577,7 +2636,8 @@ def surface( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @overload @@ -2617,7 +2677,8 @@ def surface( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: ... +) -> FacetGrid[T_DataArray]: + ... @_plot2d From 4bb57ca2f1b4af8116b14d0cca2792186c12df54 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 11:52:48 +0000 Subject: [PATCH 023/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/dataarray_plot.py | 81 ++++++++++++----------------------- 1 file changed, 27 insertions(+), 54 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index cfd46498c6f..11d7afb518f 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -348,8 +348,7 @@ def line( # type: ignore[misc,unused-ignore] # None is hashable :( add_legend: bool = True, _labels: bool = True, **kwargs: Any, -) -> list[Line3D]: - ... +) -> list[Line3D]: ... @overload @@ -376,8 +375,7 @@ def line( add_legend: bool = True, _labels: bool = True, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -404,8 +402,7 @@ def line( add_legend: bool = True, _labels: bool = True, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... # This function signature should not change so that it can use @@ -559,8 +556,7 @@ def step( # type: ignore[misc,unused-ignore] # None is hashable :( row: None = None, # no wrap -> primitive col: None = None, # no wrap -> primitive **kwargs: Any, -) -> list[Line3D]: - ... +) -> list[Line3D]: ... @overload @@ -573,8 +569,7 @@ def step( row: Hashable, # wrap -> FacetGrid col: Hashable | None = None, **kwargs: Any, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @overload @@ -587,8 +582,7 @@ def step( row: Hashable | None = None, col: Hashable, # wrap -> FacetGrid **kwargs: Any, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... def step( @@ -1161,8 +1155,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1203,8 +1196,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @overload @@ -1245,8 +1237,7 @@ def lines( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[DataArray]: - ... +) -> FacetGrid[DataArray]: ... @_plot1d @@ -1365,8 +1356,7 @@ def scatter( # type: ignore[misc,unused-ignore] # None is hashable :( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> PathCollection: - ... +) -> PathCollection: ... @overload @@ -1407,8 +1397,7 @@ def scatter( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -1449,8 +1438,7 @@ def scatter( extend: ExtendOptions = None, levels: ArrayLike | None = None, **kwargs, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @_plot1d @@ -1917,8 +1905,7 @@ def imshow( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> AxesImage: - ... +) -> AxesImage: ... @overload @@ -1958,8 +1945,7 @@ def imshow( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -1999,8 +1985,7 @@ def imshow( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @_plot2d @@ -2136,8 +2121,7 @@ def contour( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> QuadContourSet: - ... +) -> QuadContourSet: ... @overload @@ -2177,8 +2161,7 @@ def contour( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -2218,8 +2201,7 @@ def contour( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @_plot2d @@ -2272,8 +2254,7 @@ def contourf( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> QuadContourSet: - ... +) -> QuadContourSet: ... @overload @@ -2313,8 +2294,7 @@ def contourf( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -2354,8 +2334,7 @@ def contourf( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @_plot2d @@ -2408,8 +2387,7 @@ def pcolormesh( # type: ignore[misc,unused-ignore] # None is hashable :( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> QuadMesh: - ... +) -> QuadMesh: ... @overload @@ -2449,8 +2427,7 @@ def pcolormesh( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -2490,8 +2467,7 @@ def pcolormesh( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @_plot2d @@ -2595,8 +2571,7 @@ def surface( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> Poly3DCollection: - ... +) -> Poly3DCollection: ... @overload @@ -2636,8 +2611,7 @@ def surface( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @overload @@ -2677,8 +2651,7 @@ def surface( ylim: ArrayLike | None = None, norm: Normalize | None = None, **kwargs: Any, -) -> FacetGrid[T_DataArray]: - ... +) -> FacetGrid[T_DataArray]: ... @_plot2d From d5fa2c5cd28c007d28141888405767185a944e36 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 13:11:29 +0100 Subject: [PATCH 024/102] Update utils.py --- xarray/plot/utils.py | 76 ++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 6cec0cf06e2..28835b58adc 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,14 +1294,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1448,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1475,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1831,22 +1837,23 @@ def _line( self, x: float | ArrayLike, y: float | ArrayLike, - z: None = None, - s: float | ArrayLike | None = None, - c: Sequence[ColorType] | ColorType | None = None, - linestyle: LineStyleType | None = None, - cmap: str | Colormap | None = None, - norm: str | Normalize | None = None, - vmin: float | None = None, - vmax: float | None = None, - alpha: float | None = None, - linewidths: float | Sequence[float] | None = None, + z: None = ..., + s: float | ArrayLike | None = ..., + c: Sequence[ColorType] | ColorType | None = ..., + linestyle: LineStyleType | None = ..., + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + alpha: float | None = ..., + linewidths: float | Sequence[float] | None = ..., *, - edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, - plotnonfinite: bool = False, - data=None, + edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = ..., + plotnonfinite: bool = ..., + data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1854,22 +1861,23 @@ def _line( self, x: float | ArrayLike, y: float | ArrayLike, - z: float | ArrayLike = None, - s: float | ArrayLike | None = None, - c: Sequence[ColorType] | ColorType | None = None, - linestyle: LineStyleType | None = None, - cmap: str | Colormap | None = None, - norm: str | Normalize | None = None, - vmin: float | None = None, - vmax: float | None = None, - alpha: float | None = None, - linewidths: float | Sequence[float] | None = None, + z: float | ArrayLike = ..., + s: float | ArrayLike | None = ..., + c: Sequence[ColorType] | ColorType | None = ..., + linestyle: LineStyleType | None = ..., + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + alpha: float | None = ..., + linewidths: float | Sequence[float] | None = ..., *, - edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, - plotnonfinite: bool = False, - data=None, + edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = ..., + plotnonfinite: bool = ..., + data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( From 79978a45eb3f351639bd8bd7c54fb06e1bb09bc9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:12:27 +0000 Subject: [PATCH 025/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 28835b58adc..15ac0d988bf 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,16 +1294,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1448,12 +1446,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1475,12 +1471,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1852,8 +1846,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1876,8 +1869,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From 29691d05b2c9abc9366d9d34d3d837e0f2ca02e7 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 13:45:09 +0100 Subject: [PATCH 026/102] Update utils.py --- xarray/plot/utils.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 15ac0d988bf..51ca9d2618d 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -32,6 +32,7 @@ from matplotlib.ticker import FuncFormatter from matplotlib.typing import ColorType, LineStyleType from mpl_toolkits.mplot3d.art3d import Line3DCollection + from mpl_toolkits.mplot3d.axes3d import Axes3D from numpy.typing import ArrayLike from xarray.core.dataarray import DataArray @@ -1294,14 +1295,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1449,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1476,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1828,7 +1835,7 @@ def _guess_coords_to_plot( @overload def _line( - self, + self: Axes, x: float | ArrayLike, y: float | ArrayLike, z: None = ..., @@ -1846,12 +1853,13 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload def _line( - self, + self: Axes3D, x: float | ArrayLike, y: float | ArrayLike, z: float | ArrayLike = ..., @@ -1869,11 +1877,12 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( - self, + self: Axes | Axes3D, x: float | ArrayLike, y: float | ArrayLike, z: float | ArrayLike | None = None, From d9f08546502b65fc142ee0bf614487b3154d738e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:45:41 +0000 Subject: [PATCH 027/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 51ca9d2618d..f50991dd430 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1295,16 +1295,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1449,12 +1447,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1476,12 +1472,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1853,8 +1847,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1877,8 +1870,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From afc1c1baf252a66fdded740e802450226d0b1dc2 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 13:52:53 +0100 Subject: [PATCH 028/102] Update utils.py --- xarray/plot/utils.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index f50991dd430..03b3e497d5f 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1295,14 +1295,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1447,10 +1449,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1472,10 +1476,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1847,7 +1853,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1870,7 +1877,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -1911,7 +1919,7 @@ def _line( LineCollection_ = Line3DCollection add_collection_ = self.add_collection3d auto_scale = self.auto_scale_xyz - auto_scale_args = (x, y, z, self.has_data()) + auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) else: LineCollection_ = plt.matplotlib.collections.LineCollection add_collection_ = self.add_collection From 8ece6a4cc3498189c4a3addb81aa1e177ee670d7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:53:25 +0000 Subject: [PATCH 029/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 03b3e497d5f..1bf2e2d84d9 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1295,16 +1295,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1449,12 +1447,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1476,12 +1472,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1853,8 +1847,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1877,8 +1870,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From bd11e624e51736935c7b85ac8a7295c547fabccf Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 14:04:15 +0100 Subject: [PATCH 030/102] Update utils.py --- xarray/plot/utils.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 03b3e497d5f..2b4bc2dfdb7 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1918,13 +1918,19 @@ def _line( LineCollection_ = Line3DCollection add_collection_ = self.add_collection3d - auto_scale = self.auto_scale_xyz - auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) + # auto_scale = self.auto_scale_xyz + # auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) + def auto_scale(ax: Axes | Axes3D) -> None: + ax.auto_scale_xyz(x, y, z, ax.has_data()) + else: LineCollection_ = plt.matplotlib.collections.LineCollection add_collection_ = self.add_collection - auto_scale = self._request_autoscale_view - auto_scale_args = tuple() + # auto_scale = self._request_autoscale_view + # auto_scale_args = tuple() + + def auto_scale(ax: Axes | Axes3D) -> None: + ax._request_autoscale_view # Process **kwargs to handle aliases, conflicts with explicit kwargs: x, y = self._process_unit_info([("x", x), ("y", y)], kwargs) @@ -2001,7 +2007,8 @@ def _line( # self._request_autoscale_view() # self.autoscale_view() - auto_scale(*auto_scale_args) + # auto_scale(*auto_scale_args) + auto_scale(self) return collection From 3e3fd8bb58f2d0456373bacb282ffcbc6b9b4add Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 13:05:04 +0000 Subject: [PATCH 031/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index de5ac6dd441..44be03ef0b1 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1910,6 +1910,7 @@ def _line( LineCollection_ = Line3DCollection add_collection_ = self.add_collection3d + # auto_scale = self.auto_scale_xyz # auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) def auto_scale(ax: Axes | Axes3D) -> None: From f3f6554a5f7f33c36ed6bb5a9e6167fcb68acc4e Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 15:21:07 +0100 Subject: [PATCH 032/102] Update utils.py --- xarray/plot/utils.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 44be03ef0b1..6e7916d0906 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1295,14 +1295,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1447,10 +1449,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1472,10 +1476,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1847,7 +1853,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1870,7 +1877,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -1926,7 +1934,7 @@ def auto_scale(ax: Axes | Axes3D) -> None: ax._request_autoscale_view # Process **kwargs to handle aliases, conflicts with explicit kwargs: - x, y = self._process_unit_info([("x", x), ("y", y)], kwargs) + x, y = self._process_unit_info([("x", x), ("y", y)], kwargs) # ignore[union-attr] if s is None: s = np.array([rcParams["lines.linewidth"]]) From 6b70602fc1d84f90bf0706aa08c9d946fe9b77c7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 14:22:09 +0000 Subject: [PATCH 033/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 6e7916d0906..5149f103ad4 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1295,16 +1295,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1449,12 +1447,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1476,12 +1472,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1853,8 +1847,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1877,8 +1870,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From 768f68e150c6aa8096d3fa6d20fdc7888f2682bf Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 15:24:26 +0100 Subject: [PATCH 034/102] Update utils.py --- xarray/plot/utils.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 5149f103ad4..51445d7706d 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1910,20 +1910,13 @@ def _line( LineCollection_ = Line3DCollection add_collection_ = self.add_collection3d - - # auto_scale = self.auto_scale_xyz - # auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) - def auto_scale(ax: Axes | Axes3D) -> None: - ax.auto_scale_xyz(x, y, z, ax.has_data()) - + auto_scale = self.auto_scale_xyz + auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) else: LineCollection_ = plt.matplotlib.collections.LineCollection add_collection_ = self.add_collection - # auto_scale = self._request_autoscale_view - # auto_scale_args = tuple() - - def auto_scale(ax: Axes | Axes3D) -> None: - ax._request_autoscale_view + auto_scale = self._request_autoscale_view + auto_scale_args = tuple() # Process **kwargs to handle aliases, conflicts with explicit kwargs: x, y = self._process_unit_info([("x", x), ("y", y)], kwargs) # ignore[union-attr] @@ -2000,8 +1993,7 @@ def auto_scale(ax: Axes | Axes3D) -> None: # self._request_autoscale_view() # self.autoscale_view() - # auto_scale(*auto_scale_args) - auto_scale(self) + auto_scale(*auto_scale_args) return collection From b9af902038cb27015f2713a720cafe5f39764bcd Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 15:32:24 +0100 Subject: [PATCH 035/102] Update utils.py --- xarray/plot/utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 51445d7706d..17861e250c8 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -32,7 +32,6 @@ from matplotlib.ticker import FuncFormatter from matplotlib.typing import ColorType, LineStyleType from mpl_toolkits.mplot3d.art3d import Line3DCollection - from mpl_toolkits.mplot3d.axes3d import Axes3D from numpy.typing import ArrayLike from xarray.core.dataarray import DataArray @@ -1829,7 +1828,7 @@ def _guess_coords_to_plot( @overload def _line( - self: Axes, + self, # Axes, x: float | ArrayLike, y: float | ArrayLike, z: None = ..., @@ -1852,7 +1851,7 @@ def _line( @overload def _line( - self: Axes3D, + self, # Axes3D, x: float | ArrayLike, y: float | ArrayLike, z: float | ArrayLike = ..., @@ -1874,7 +1873,7 @@ def _line( def _line( - self: Axes | Axes3D, + self, # Axes | Axes3D x: float | ArrayLike, y: float | ArrayLike, z: float | ArrayLike | None = None, From dcabb85e6dcde0bd1f38f3c14684ba3d33e2e831 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 15:54:40 +0100 Subject: [PATCH 036/102] s can be float, no __len__ on those --- xarray/plot/utils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 17861e250c8..e8afd1a2c89 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1922,10 +1922,11 @@ def _line( if s is None: s = np.array([rcParams["lines.linewidth"]]) - # s = np.ma.ravel(s) - if len(s) not in (1, x.size) or ( - not np.issubdtype(s.dtype, np.floating) - and not np.issubdtype(s.dtype, np.integer) + + s_: np.ndarray = np.ma.ravel(s) + if len(s_) not in (1, x.size) or ( + not np.issubdtype(s_.dtype, np.floating) + and not np.issubdtype(s_.dtype, np.integer) ): raise ValueError( "s must be a scalar, " "or float array-like with the same size as x and y" @@ -1959,7 +1960,7 @@ def _line( # Might be scary duplicating number of elements? # xyz = list(np.repeat(v, 2) for v in (x, y, z) if v is not None) # c = np.repeat(c, 2) # TODO: Off by one? - # s = np.repeat(s, 2) + # s_ = np.repeat(s_, 2) # if drawstyle == "steps-pre": # xyz[-1][:-1] = xyz[-1][1:] # elif drawstyle == "steps-post": @@ -1976,7 +1977,7 @@ def _line( collection = LineCollection_( segments, - linewidths=s, + linewidths=s_, linestyles="solid", ) # collection.set_transform(plt.matplotlib.transforms.IdentityTransform()) From 5690a4b018fc3cc830ef4aad2d0ea7a438efa12b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:00:35 +0100 Subject: [PATCH 037/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 11d7afb518f..6ad3512a682 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1313,7 +1313,7 @@ def lines( if len(plts_np) == 2: # return ax.scatter(plts_np[0], plts_np[1], **kwargs) - return _line(ax, plts_np[0], plts_np[1], **kwargs) + return _line(ax, plts_np[0], plts_np[1], None, **kwargs) raise ValueError("At least two variables required for a lines plot.") From 2ff874268637b790a3e00564e3c4e7158d1caf0d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:05:49 +0100 Subject: [PATCH 038/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 6ad3512a682..58ba9dcc590 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1309,11 +1309,11 @@ def lines( assert isinstance(ax, mpl_toolkits.mplot3d.axes3d.Axes3D) # return ax.scatter(xplt_np, yplt_np, zplt_np, **kwargs) - return _line(ax, xplt_np, yplt_np, zplt_np, **kwargs) + return _line(ax, *plts_np, **kwargs) if len(plts_np) == 2: # return ax.scatter(plts_np[0], plts_np[1], **kwargs) - return _line(ax, plts_np[0], plts_np[1], None, **kwargs) + return _line(ax, *plts_np, **kwargs) raise ValueError("At least two variables required for a lines plot.") From 7bb8c326017673ac134f055b8450d42f49a5dbf0 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:18:14 +0100 Subject: [PATCH 039/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 194 +++++++++++++++++----------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 58ba9dcc590..78d1cc65fc9 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1121,39 +1121,39 @@ def _add_labels( def lines( darray: DataArray, *args: Any, - x: Hashable | None = None, - y: Hashable | None = None, - z: Hashable | None = None, - hue: Hashable | None = None, - hue_style: HueStyleOptions = None, - markersize: Hashable | None = None, - linewidth: Hashable | None = None, - figsize: Iterable[float] | None = None, - size: float | None = None, - aspect: float | None = None, - ax: Axes | None = None, - row: None = None, # no wrap -> primitive - col: None = None, # no wrap -> primitive - col_wrap: int | None = None, - xincrease: bool | None = True, - yincrease: bool | None = True, - add_legend: bool | None = None, - add_colorbar: bool | None = None, - add_labels: bool | Iterable[bool] = True, - add_title: bool = True, - subplot_kws: dict[str, Any] | None = None, - xscale: ScaleOptions = None, - yscale: ScaleOptions = None, - xticks: ArrayLike | None = None, - yticks: ArrayLike | None = None, - xlim: ArrayLike | None = None, - ylim: ArrayLike | None = None, - cmap: str | Colormap | None = None, - vmin: float | None = None, - vmax: float | None = None, - norm: Normalize | None = None, - extend: ExtendOptions = None, - levels: ArrayLike | None = None, + x: Hashable | None = ..., + y: Hashable | None = ..., + z: Hashable | None = ..., + hue: Hashable | None = ..., + hue_style: HueStyleOptions = ..., + markersize: Hashable | None = ..., + linewidth: Hashable | None = ..., + figsize: Iterable[float] | None = ..., + size: float | None = ..., + aspect: float | None = ..., + ax: Axes | None = ..., + row: None = ..., # no wrap -> primitive + col: None = ..., # no wrap -> primitive + col_wrap: int | None = ..., + xincrease: bool | None = ..., + yincrease: bool | None = ..., + add_legend: bool | None = ..., + add_colorbar: bool | None = ..., + add_labels: bool | Iterable[bool] = ..., + add_title: bool = ..., + subplot_kws: dict[str, Any] | None = ..., + xscale: ScaleOptions = ..., + yscale: ScaleOptions = ..., + xticks: ArrayLike | None = ..., + yticks: ArrayLike | None = ..., + xlim: ArrayLike | None = ..., + ylim: ArrayLike | None = ..., + cmap: str | Colormap | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + norm: Normalize | None = ..., + extend: ExtendOptions = ..., + levels: ArrayLike | None = ..., **kwargs, ) -> LineCollection: ... @@ -1162,39 +1162,39 @@ def lines( def lines( darray: DataArray, *args: Any, - x: Hashable | None = None, - y: Hashable | None = None, - z: Hashable | None = None, - hue: Hashable | None = None, - hue_style: HueStyleOptions = None, - markersize: Hashable | None = None, - linewidth: Hashable | None = None, - figsize: Iterable[float] | None = None, - size: float | None = None, - aspect: float | None = None, - ax: Axes | None = None, - row: Hashable | None = None, + x: Hashable | None = ..., + y: Hashable | None = ..., + z: Hashable | None = ..., + hue: Hashable | None = ..., + hue_style: HueStyleOptions = ..., + markersize: Hashable | None = ..., + linewidth: Hashable | None = ..., + figsize: Iterable[float] | None = ..., + size: float | None = ..., + aspect: float | None = ..., + ax: Axes | None = ..., + row: Hashable | None = ..., col: Hashable, # wrap -> FacetGrid - col_wrap: int | None = None, - xincrease: bool | None = True, - yincrease: bool | None = True, - add_legend: bool | None = None, - add_colorbar: bool | None = None, - add_labels: bool | Iterable[bool] = True, - add_title: bool = True, - subplot_kws: dict[str, Any] | None = None, - xscale: ScaleOptions = None, - yscale: ScaleOptions = None, - xticks: ArrayLike | None = None, - yticks: ArrayLike | None = None, - xlim: ArrayLike | None = None, - ylim: ArrayLike | None = None, - cmap: str | Colormap | None = None, - vmin: float | None = None, - vmax: float | None = None, - norm: Normalize | None = None, - extend: ExtendOptions = None, - levels: ArrayLike | None = None, + col_wrap: int | None = ..., + xincrease: bool | None = ..., + yincrease: bool | None = ..., + add_legend: bool | None = ..., + add_colorbar: bool | None = ..., + add_labels: bool | Iterable[bool] = ..., + add_title: bool = ..., + subplot_kws: dict[str, Any] | None = ..., + xscale: ScaleOptions = ..., + yscale: ScaleOptions = ..., + xticks: ArrayLike | None = ..., + yticks: ArrayLike | None = ..., + xlim: ArrayLike | None = ..., + ylim: ArrayLike | None = ..., + cmap: str | Colormap | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + norm: Normalize | None = ..., + extend: ExtendOptions = ..., + levels: ArrayLike | None = ..., **kwargs, ) -> FacetGrid[DataArray]: ... @@ -1203,39 +1203,39 @@ def lines( def lines( darray: DataArray, *args: Any, - x: Hashable | None = None, - y: Hashable | None = None, - z: Hashable | None = None, - hue: Hashable | None = None, - hue_style: HueStyleOptions = None, - markersize: Hashable | None = None, - linewidth: Hashable | None = None, - figsize: Iterable[float] | None = None, - size: float | None = None, - aspect: float | None = None, - ax: Axes | None = None, + x: Hashable | None = ..., + y: Hashable | None = ..., + z: Hashable | None = ..., + hue: Hashable | None = ..., + hue_style: HueStyleOptions = ..., + markersize: Hashable | None = ..., + linewidth: Hashable | None = ..., + figsize: Iterable[float] | None = ..., + size: float | None = ..., + aspect: float | None = ..., + ax: Axes | None = ..., row: Hashable, # wrap -> FacetGrid - col: Hashable | None = None, - col_wrap: int | None = None, - xincrease: bool | None = True, - yincrease: bool | None = True, - add_legend: bool | None = None, - add_colorbar: bool | None = None, - add_labels: bool | Iterable[bool] = True, - add_title: bool = True, - subplot_kws: dict[str, Any] | None = None, - xscale: ScaleOptions = None, - yscale: ScaleOptions = None, - xticks: ArrayLike | None = None, - yticks: ArrayLike | None = None, - xlim: ArrayLike | None = None, - ylim: ArrayLike | None = None, - cmap: str | Colormap | None = None, - vmin: float | None = None, - vmax: float | None = None, - norm: Normalize | None = None, - extend: ExtendOptions = None, - levels: ArrayLike | None = None, + col: Hashable | None = ..., + col_wrap: int | None = ..., + xincrease: bool | None = ..., + yincrease: bool | None = ..., + add_legend: bool | None = ..., + add_colorbar: bool | None = ..., + add_labels: bool | Iterable[bool] = ..., + add_title: bool = ..., + subplot_kws: dict[str, Any] | None = ..., + xscale: ScaleOptions = ..., + yscale: ScaleOptions = ..., + xticks: ArrayLike | None = ..., + yticks: ArrayLike | None = ..., + xlim: ArrayLike | None = ..., + ylim: ArrayLike | None = ..., + cmap: str | Colormap | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + norm: Normalize | None = ..., + extend: ExtendOptions = ..., + levels: ArrayLike | None = ..., **kwargs, ) -> FacetGrid[DataArray]: ... From a43d685b4b21615d0295490ccab7d54b0d25a589 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:20:14 +0100 Subject: [PATCH 040/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 196 +++++++++++++++++----------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 78d1cc65fc9..efadd5e7aa2 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1118,42 +1118,42 @@ def _add_labels( @overload -def lines( +def lines( # type: ignore[misc,unused-ignore] # None is hashable :( darray: DataArray, *args: Any, - x: Hashable | None = ..., - y: Hashable | None = ..., - z: Hashable | None = ..., - hue: Hashable | None = ..., - hue_style: HueStyleOptions = ..., - markersize: Hashable | None = ..., - linewidth: Hashable | None = ..., - figsize: Iterable[float] | None = ..., - size: float | None = ..., - aspect: float | None = ..., - ax: Axes | None = ..., - row: None = ..., # no wrap -> primitive - col: None = ..., # no wrap -> primitive - col_wrap: int | None = ..., - xincrease: bool | None = ..., - yincrease: bool | None = ..., - add_legend: bool | None = ..., - add_colorbar: bool | None = ..., - add_labels: bool | Iterable[bool] = ..., - add_title: bool = ..., - subplot_kws: dict[str, Any] | None = ..., - xscale: ScaleOptions = ..., - yscale: ScaleOptions = ..., - xticks: ArrayLike | None = ..., - yticks: ArrayLike | None = ..., - xlim: ArrayLike | None = ..., - ylim: ArrayLike | None = ..., - cmap: str | Colormap | None = ..., - vmin: float | None = ..., - vmax: float | None = ..., - norm: Normalize | None = ..., - extend: ExtendOptions = ..., - levels: ArrayLike | None = ..., + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: None = None, # no wrap -> primitive + col: None = None, # no wrap -> primitive + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, **kwargs, ) -> LineCollection: ... @@ -1162,39 +1162,39 @@ def lines( def lines( darray: DataArray, *args: Any, - x: Hashable | None = ..., - y: Hashable | None = ..., - z: Hashable | None = ..., - hue: Hashable | None = ..., - hue_style: HueStyleOptions = ..., - markersize: Hashable | None = ..., - linewidth: Hashable | None = ..., - figsize: Iterable[float] | None = ..., - size: float | None = ..., - aspect: float | None = ..., - ax: Axes | None = ..., - row: Hashable | None = ..., + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable | None = None, col: Hashable, # wrap -> FacetGrid - col_wrap: int | None = ..., - xincrease: bool | None = ..., - yincrease: bool | None = ..., - add_legend: bool | None = ..., - add_colorbar: bool | None = ..., - add_labels: bool | Iterable[bool] = ..., - add_title: bool = ..., - subplot_kws: dict[str, Any] | None = ..., - xscale: ScaleOptions = ..., - yscale: ScaleOptions = ..., - xticks: ArrayLike | None = ..., - yticks: ArrayLike | None = ..., - xlim: ArrayLike | None = ..., - ylim: ArrayLike | None = ..., - cmap: str | Colormap | None = ..., - vmin: float | None = ..., - vmax: float | None = ..., - norm: Normalize | None = ..., - extend: ExtendOptions = ..., - levels: ArrayLike | None = ..., + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, **kwargs, ) -> FacetGrid[DataArray]: ... @@ -1203,39 +1203,39 @@ def lines( def lines( darray: DataArray, *args: Any, - x: Hashable | None = ..., - y: Hashable | None = ..., - z: Hashable | None = ..., - hue: Hashable | None = ..., - hue_style: HueStyleOptions = ..., - markersize: Hashable | None = ..., - linewidth: Hashable | None = ..., - figsize: Iterable[float] | None = ..., - size: float | None = ..., - aspect: float | None = ..., - ax: Axes | None = ..., + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, row: Hashable, # wrap -> FacetGrid - col: Hashable | None = ..., - col_wrap: int | None = ..., - xincrease: bool | None = ..., - yincrease: bool | None = ..., - add_legend: bool | None = ..., - add_colorbar: bool | None = ..., - add_labels: bool | Iterable[bool] = ..., - add_title: bool = ..., - subplot_kws: dict[str, Any] | None = ..., - xscale: ScaleOptions = ..., - yscale: ScaleOptions = ..., - xticks: ArrayLike | None = ..., - yticks: ArrayLike | None = ..., - xlim: ArrayLike | None = ..., - ylim: ArrayLike | None = ..., - cmap: str | Colormap | None = ..., - vmin: float | None = ..., - vmax: float | None = ..., - norm: Normalize | None = ..., - extend: ExtendOptions = ..., - levels: ArrayLike | None = ..., + col: Hashable | None = None, + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend: ExtendOptions = None, + levels: ArrayLike | None = None, **kwargs, ) -> FacetGrid[DataArray]: ... From 3ada3579904dd51ab4d99530492bbd83f3896510 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:29:50 +0100 Subject: [PATCH 041/102] add Hashable vs None ignores --- xarray/plot/accessor.py | 122 +++++++++++++++++++++++++++++++++- xarray/plot/dataarray_plot.py | 2 +- xarray/plot/dataset_plot.py | 2 +- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/xarray/plot/accessor.py b/xarray/plot/accessor.py index 9df4b22554a..426b0b80497 100644 --- a/xarray/plot/accessor.py +++ b/xarray/plot/accessor.py @@ -135,6 +135,126 @@ def line( def line(self, *args, **kwargs) -> list[Line3D] | FacetGrid[DataArray]: return dataarray_plot.line(self._da, *args, **kwargs) + @overload + def lines( # type: ignore[misc,unused-ignore] # None is hashable :( + self, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: None = None, # no wrap -> primitive + col: None = None, # no wrap -> primitive + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap=None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend=None, + levels=None, + **kwargs: Any, + ) -> LineCollection: ... + + @overload + def lines( + self, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable | None = None, + col: Hashable, # wrap -> FacetGrid + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap=None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend=None, + levels=None, + **kwargs: Any, + ) -> FacetGrid[DataArray]: ... + + @overload + def lines( + self, + *args: Any, + x: Hashable | None = None, + y: Hashable | None = None, + z: Hashable | None = None, + hue: Hashable | None = None, + hue_style: HueStyleOptions = None, + markersize: Hashable | None = None, + linewidth: Hashable | None = None, + figsize: Iterable[float] | None = None, + size: float | None = None, + aspect: float | None = None, + ax: Axes | None = None, + row: Hashable, # wrap -> FacetGrid + col: Hashable | None = None, + col_wrap: int | None = None, + xincrease: bool | None = True, + yincrease: bool | None = True, + add_legend: bool | None = None, + add_colorbar: bool | None = None, + add_labels: bool | Iterable[bool] = True, + add_title: bool = True, + subplot_kws: dict[str, Any] | None = None, + xscale: ScaleOptions = None, + yscale: ScaleOptions = None, + xticks: ArrayLike | None = None, + yticks: ArrayLike | None = None, + xlim: ArrayLike | None = None, + ylim: ArrayLike | None = None, + cmap=None, + vmin: float | None = None, + vmax: float | None = None, + norm: Normalize | None = None, + extend=None, + levels=None, + **kwargs: Any, + ) -> FacetGrid[DataArray]: ... + @functools.wraps(dataarray_plot.lines) def lines(self, *args, **kwargs) -> LineCollection | FacetGrid[DataArray]: return dataarray_plot.lines(self._da, *args, **kwargs) @@ -928,7 +1048,7 @@ def __call__(self, *args, **kwargs) -> NoReturn: ) @overload - def lines( + def lines( # type: ignore[misc,unused-ignore] # None is hashable :( self, *args: Any, x: Hashable | None = None, diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index efadd5e7aa2..bdfc622efb5 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -190,7 +190,7 @@ def _prepare_plot1d_data( # When stacking dims the lines will continue connecting. For floats # this can be solved by adding a nan element in between the flattening # points: - dims_T = [] + dims_T: list[Hashable] = [] if np.issubdtype(darray.dtype, np.floating): i = 0 for v in ("z", "x"): diff --git a/xarray/plot/dataset_plot.py b/xarray/plot/dataset_plot.py index d933f51f13e..f588d4e67dc 100644 --- a/xarray/plot/dataset_plot.py +++ b/xarray/plot/dataset_plot.py @@ -914,7 +914,7 @@ def scatter( @overload -def lines( +def lines( # type: ignore[misc,unused-ignore] # None is hashable :( ds: Dataset, *args: Any, x: Hashable | None = None, From 6911b66efc85aa8a3804bb616286dc80c27b1b3c Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:38:36 +0100 Subject: [PATCH 042/102] Update utils.py --- xarray/plot/utils.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index e8afd1a2c89..019c1ea842e 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1903,6 +1903,11 @@ def _line( rcParams = plt.matplotlib.rcParams + # Process **kwargs to handle aliases, conflicts with explicit kwargs: + x_: np.ndarray + y_: np.ndarray + x_, y_ = self._process_unit_info([("x", x), ("y", y)], kwargs) # ignore[union-attr] + # Handle z inputs: if z is not None: from mpl_toolkits.mplot3d.art3d import Line3DCollection @@ -1910,21 +1915,18 @@ def _line( LineCollection_ = Line3DCollection add_collection_ = self.add_collection3d auto_scale = self.auto_scale_xyz - auto_scale_args: tuple[Any, ...] = (x, y, z, self.has_data()) + auto_scale_args: tuple[Any, ...] = (x_, y_, z, self.has_data()) else: LineCollection_ = plt.matplotlib.collections.LineCollection add_collection_ = self.add_collection auto_scale = self._request_autoscale_view auto_scale_args = tuple() - # Process **kwargs to handle aliases, conflicts with explicit kwargs: - x, y = self._process_unit_info([("x", x), ("y", y)], kwargs) # ignore[union-attr] - if s is None: s = np.array([rcParams["lines.linewidth"]]) s_: np.ndarray = np.ma.ravel(s) - if len(s_) not in (1, x.size) or ( + if len(s_) not in (1, x_.size) or ( not np.issubdtype(s_.dtype, np.floating) and not np.issubdtype(s_.dtype, np.integer) ): @@ -1937,7 +1939,7 @@ def _line( c, edgecolors, kwargs, - x.size, + x_.size, get_next_color_func=self._get_patches_for_fill.get_next_color, ) @@ -1948,17 +1950,17 @@ def _line( drawstyle = kwargs.pop("drawstyle", "default") if drawstyle == "default": # Draw linear lines: - xyz = list(v for v in (x, y, z) if v is not None) + xyz = list(v for v in (x_, y_, z) if v is not None) else: # Draw stepwise lines: from matplotlib.cbook import STEP_LOOKUP_MAP step_func = STEP_LOOKUP_MAP[drawstyle] - xyz = step_func(*tuple(v for v in (x, y, z) if v is not None)) + xyz = step_func(*tuple(v for v in (x_, y_, z) if v is not None)) # Create steps by repeating all elements, then roll the last array by 1: # Might be scary duplicating number of elements? - # xyz = list(np.repeat(v, 2) for v in (x, y, z) if v is not None) + # xyz = list(np.repeat(v, 2) for v in (x_, y_, z) if v is not None) # c = np.repeat(c, 2) # TODO: Off by one? # s_ = np.repeat(s_, 2) # if drawstyle == "steps-pre": From 33a151f6337b722b8523cda85475f9436d98f8d0 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 10 Mar 2024 17:51:35 +0100 Subject: [PATCH 043/102] clean up --- xarray/plot/dataarray_plot.py | 37 ++--------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index bdfc622efb5..59a38363b53 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1160,7 +1160,7 @@ def lines( # type: ignore[misc,unused-ignore] # None is hashable :( @overload def lines( - darray: DataArray, + darray: T_DataArray, *args: Any, x: Hashable | None = None, y: Hashable | None = None, @@ -1201,7 +1201,7 @@ def lines( @overload def lines( - darray: DataArray, + darray: T_DataArray, *args: Any, x: Hashable | None = None, y: Hashable | None = None, @@ -1252,37 +1252,6 @@ def lines( Line plot of DataArray index against values Wraps :func:`matplotlib:matplotlib.collections.LineCollection` """ - # if "u" in kwargs or "v" in kwargs: - # raise ValueError("u, v are not allowed in scatter plots.") - - # zplt: DataArray | None = kwargs.pop("zplt", None) - # hueplt: DataArray | None = kwargs.pop("hueplt", None) - # sizeplt: DataArray | None = kwargs.pop("sizeplt", None) - - # if hueplt is not None: - # kwargs.update(c=hueplt.to_numpy().ravel()) - - # if sizeplt is not None: - # kwargs.update(s=sizeplt.to_numpy().ravel()) - - # # # Remove pd.Intervals if contained in xplt.values and/or yplt.values. - # # xplt_val, yplt_val, x_suffix, y_suffix, kwargs = _resolve_intervals_1dplot( - # # xplt.to_numpy(), yplt.to_numpy(), kwargs - # # ) - # # zplt_val = zplt.to_numpy() if zplt is not None else None - # # z_suffix = "" # TODO: to _resolve_intervals? - # # _ensure_plottable(xplt_val, yplt_val) - - # axis_order = ["x", "y", "z"] - - # plts_dict: dict[str, DataArray | None] = dict(x=xplt, y=yplt, z=zplt) - # plts_or_none = [plts_dict[v] for v in axis_order] - # plts = [p for p in plts_or_none if p is not None] - # primitive = _line(ax, *[p.to_numpy().ravel() for p in plts], **kwargs) - # _add_labels(add_labels, plts, ("", "", ""), (True, False, False), ax) - - # return primitive - if "u" in kwargs or "v" in kwargs: raise ValueError("u, v are not allowed in lines plots.") @@ -1308,11 +1277,9 @@ def lines( import mpl_toolkits assert isinstance(ax, mpl_toolkits.mplot3d.axes3d.Axes3D) - # return ax.scatter(xplt_np, yplt_np, zplt_np, **kwargs) return _line(ax, *plts_np, **kwargs) if len(plts_np) == 2: - # return ax.scatter(plts_np[0], plts_np[1], **kwargs) return _line(ax, *plts_np, **kwargs) raise ValueError("At least two variables required for a lines plot.") From 89103960f22dc387f4660e67e50f7b704647862e Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:36:58 +0100 Subject: [PATCH 044/102] Fix color="k" --- xarray/plot/utils.py | 89 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 019c1ea842e..9c65a19f78d 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1900,9 +1900,42 @@ def _line( """ import matplotlib.pyplot as plt + import matplotlib.cbook as cbook + import matplotlib.collections as mcoll + from matplotlib import _api rcParams = plt.matplotlib.rcParams + def _parse_lines_color_args( + self, c, edgecolors, kwargs, xsize, get_next_color_func + ): + if edgecolors is None: + # Use "face" instead of rcParams['scatter.edgecolors'] + edgecolors = "face" + + c, colors, edgecolors = self._parse_scatter_color_args( + c, + edgecolors, + kwargs, + x_.size, + get_next_color_func=self._get_patches_for_fill.get_next_color, + ) + + return c, colors, edgecolors + + # add edgecolors and linewidths to kwargs so they + # can be processed by normailze_kwargs + if edgecolors is not None: + kwargs.update({"edgecolors": edgecolors}) + if linewidths is not None: + kwargs.update({"linewidths": linewidths}) + + kwargs = cbook.normalize_kwargs(kwargs, mcoll.Collection) + # re direct linewidth and edgecolor so it can be + # further processed by the rest of the function + linewidths = kwargs.pop("linewidth", None) + edgecolors = kwargs.pop("edgecolor", None) + # Process **kwargs to handle aliases, conflicts with explicit kwargs: x_: np.ndarray y_: np.ndarray @@ -1934,8 +1967,12 @@ def _line( "s must be a scalar, " "or float array-like with the same size as x and y" ) - edgecolors or kwargs.get("edgecolor", None) - c, colors, edgecolors = self._parse_scatter_color_args( + # get the original edgecolor the user passed before we normalize + orig_edgecolor = edgecolors + if edgecolors is None: + orig_edgecolor = kwargs.get("edgecolor", None) + c, colors, edgecolors = _parse_lines_color_args( + self, c, edgecolors, kwargs, @@ -1943,6 +1980,27 @@ def _line( get_next_color_func=self._get_patches_for_fill.get_next_color, ) + print(f"{edgecolors=}") + if plotnonfinite and colors is None: + c = np.ma.masked_invalid(c) + x, y, s, edgecolors, linewidths = cbook._combine_masks( + x, y, s, edgecolors, linewidths + ) + else: + x, y, s, c, colors, edgecolors, linewidths = cbook._combine_masks( + x, y, s, c, colors, edgecolors, linewidths + ) + + # Unmask edgecolors if it was actually a single RGB or RGBA. + if ( + x.size in (3, 4) + and np.ma.is_masked(edgecolors) + and not np.ma.is_masked(orig_edgecolor) + ): + edgecolors = edgecolors.data + + # scales = s # Renamed for readability below. + # load default linestyle from rcParams if linestyle is None: linestyle = rcParams["lines.linestyle"] @@ -1958,20 +2016,6 @@ def _line( step_func = STEP_LOOKUP_MAP[drawstyle] xyz = step_func(*tuple(v for v in (x_, y_, z) if v is not None)) - # Create steps by repeating all elements, then roll the last array by 1: - # Might be scary duplicating number of elements? - # xyz = list(np.repeat(v, 2) for v in (x_, y_, z) if v is not None) - # c = np.repeat(c, 2) # TODO: Off by one? - # s_ = np.repeat(s_, 2) - # if drawstyle == "steps-pre": - # xyz[-1][:-1] = xyz[-1][1:] - # elif drawstyle == "steps-post": - # xyz[-1][1:] = xyz[-1][:-1] - # else: - # raise NotImplementedError( - # f"Allowed values are: 'default', 'steps-pre', 'steps-post', got {drawstyle}." - # ) - # Broadcast arrays to correct format: # https://stackoverflow.com/questions/42215777/matplotlib-line-color-in-3d points = np.stack(np.broadcast_arrays(*xyz), axis=-1).reshape(-1, 1, len(xyz)) @@ -1981,6 +2025,9 @@ def _line( segments, linewidths=s_, linestyles="solid", + facecolors=colors, + edgecolors=edgecolors, + alpha=alpha, ) # collection.set_transform(plt.matplotlib.transforms.IdentityTransform()) collection.update(kwargs) @@ -1990,6 +2037,16 @@ def _line( collection.set_cmap(cmap) collection.set_norm(norm) collection._scale_norm(norm, vmin, vmax) + else: + extra_kwargs = {"cmap": cmap, "norm": norm, "vmin": vmin, "vmax": vmax} + extra_keys = [k for k, v in extra_kwargs.items() if v is not None] + if any(extra_keys): + keys_str = ", ".join(f"'{k}'" for k in extra_keys) + _api.warn_external( + "No data for colormapping provided via 'c'. " + f"Parameters {keys_str} will be ignored" + ) + collection._internal_update(kwargs) add_collection_(collection) From 6def42696958854f13da9137a26e587f6eb37871 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:33:33 +0100 Subject: [PATCH 045/102] cleanup --- xarray/plot/utils.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 9c65a19f78d..69b3e93bb35 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1980,7 +1980,6 @@ def _parse_lines_color_args( get_next_color_func=self._get_patches_for_fill.get_next_color, ) - print(f"{edgecolors=}") if plotnonfinite and colors is None: c = np.ma.masked_invalid(c) x, y, s, edgecolors, linewidths = cbook._combine_masks( @@ -2024,10 +2023,11 @@ def _parse_lines_color_args( collection = LineCollection_( segments, linewidths=s_, - linestyles="solid", + linestyles=linestyle, facecolors=colors, edgecolors=edgecolors, alpha=alpha, + # offset_transform=kwargs.pop("transform", self.transData), ) # collection.set_transform(plt.matplotlib.transforms.IdentityTransform()) collection.update(kwargs) @@ -2050,8 +2050,6 @@ def _parse_lines_color_args( add_collection_(collection) - # self._request_autoscale_view() - # self.autoscale_view() auto_scale(*auto_scale_args) return collection From ae3f6239565cef796da2a504bbfd965eeff9c417 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:34:13 +0100 Subject: [PATCH 046/102] Add tests for color and linestyle --- xarray/tests/test_plot.py | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 3622a4f4eaf..8b46b6396fd 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3395,3 +3395,43 @@ def test_plot1d_filtered_nulls() -> None: actual = pc.get_offsets().shape[0] assert expected == actual + + +@requires_matplotlib +@pytest.mark.parametrize("plotfunc", ["lines"]) +def test_plot1d_lines_color(plotfunc: str, x="z", color="b") -> None: + from matplotlib.colors import to_rgba_array + + ds = xr.tutorial.scatter_example_dataset(seed=42) + + darray = ds.A.sel(x=0, y=0) + + with figure_context(): + fig, ax = plt.subplots() + getattr(darray.plot, plotfunc)(x=x, color=color) + coll = ax.collections[0] + + # Make sure color is respected: + expected_color = to_rgba_array(color) + actual_color = coll.get_edgecolor() + assert np.testing.assert_allclose(expected_color, actual_color) + + +@requires_matplotlib +@pytest.mark.parametrize("plotfunc", ["lines"]) +def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> None: + from matplotlib.lines import _get_dash_pattern + + ds = xr.tutorial.scatter_example_dataset(seed=42) + + darray = ds.A.sel(x=0, y=0) + + with figure_context(): + fig, ax = plt.subplots() + getattr(darray.plot, plotfunc)(x=x, linestyle=linestyle) + coll = ax.collections[0] + + # Make sure linestyle is respected: + expected_linestyle = _get_dash_pattern(linestyle) + actual_linestyle = coll.get_linestyle() + assert np.testing.assert_allclose(expected_linestyle, actual_linestyle) From 164d15e012c7a529a45d031cada8fab3bf7372b8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:34:50 +0000 Subject: [PATCH 047/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 69b3e93bb35..621e0aec334 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1899,9 +1899,9 @@ def _line( support it directly, just like PatchCollection doesn't either. """ - import matplotlib.pyplot as plt import matplotlib.cbook as cbook import matplotlib.collections as mcoll + import matplotlib.pyplot as plt from matplotlib import _api rcParams = plt.matplotlib.rcParams From 207133f45456fc2ae625c012f48d4056c2333639 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:43:28 +0100 Subject: [PATCH 048/102] Update test_plot.py --- xarray/tests/test_plot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 8b46b6396fd..10f94c6d3fd 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3420,7 +3420,8 @@ def test_plot1d_lines_color(plotfunc: str, x="z", color="b") -> None: @requires_matplotlib @pytest.mark.parametrize("plotfunc", ["lines"]) def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> None: - from matplotlib.lines import _get_dash_pattern + # TODO: Is there a public function that converts linestyle to dash pattern? + from matplotlib.lines import _get_dash_pattern # type: ignore[attr-defined] ds = xr.tutorial.scatter_example_dataset(seed=42) From 62bbcc8ba4e9684749c6fb5eaabe7b28f883cced Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:29:23 +0100 Subject: [PATCH 049/102] Update test_plot.py --- xarray/tests/test_plot.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 10f94c6d3fd..93a5de1dc25 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3421,7 +3421,7 @@ def test_plot1d_lines_color(plotfunc: str, x="z", color="b") -> None: @pytest.mark.parametrize("plotfunc", ["lines"]) def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> None: # TODO: Is there a public function that converts linestyle to dash pattern? - from matplotlib.lines import _get_dash_pattern # type: ignore[attr-defined] + from matplotlib.lines import _get_dash_pattern, _scale_dashes # type: ignore[attr-defined] ds = xr.tutorial.scatter_example_dataset(seed=42) @@ -3433,6 +3433,7 @@ def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> Non coll = ax.collections[0] # Make sure linestyle is respected: - expected_linestyle = _get_dash_pattern(linestyle) + w = coll.get_linewidth().item() + expected_linestyle = [_scale_dashes(*_get_dash_pattern(linestyle), w)] actual_linestyle = coll.get_linestyle() - assert np.testing.assert_allclose(expected_linestyle, actual_linestyle) + assert expected_linestyle == actual_linestyle From dac8746ff981f70b95b1579ddf44c488f5080d7d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:29:59 +0000 Subject: [PATCH 050/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/tests/test_plot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 93a5de1dc25..dac6c4e57cf 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3421,7 +3421,10 @@ def test_plot1d_lines_color(plotfunc: str, x="z", color="b") -> None: @pytest.mark.parametrize("plotfunc", ["lines"]) def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> None: # TODO: Is there a public function that converts linestyle to dash pattern? - from matplotlib.lines import _get_dash_pattern, _scale_dashes # type: ignore[attr-defined] + from matplotlib.lines import ( # type: ignore[attr-defined] + _get_dash_pattern, + _scale_dashes, + ) ds = xr.tutorial.scatter_example_dataset(seed=42) From 35784427051368bd42c3c6c78d5fc07359e5e469 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 21 Mar 2024 00:20:25 +0100 Subject: [PATCH 051/102] assert not needed --- xarray/tests/test_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index dac6c4e57cf..9864dea104c 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3414,7 +3414,7 @@ def test_plot1d_lines_color(plotfunc: str, x="z", color="b") -> None: # Make sure color is respected: expected_color = to_rgba_array(color) actual_color = coll.get_edgecolor() - assert np.testing.assert_allclose(expected_color, actual_color) + np.testing.assert_allclose(expected_color, actual_color) @requires_matplotlib From 07fffb3b728f9334851d71837679acfbba35ffb6 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 21 Mar 2024 00:32:55 +0100 Subject: [PATCH 052/102] Update utils.py --- xarray/plot/utils.py | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 621e0aec334..8e5858c5972 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,14 +1294,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1448,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1475,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1846,7 +1852,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1869,7 +1876,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -1939,7 +1947,9 @@ def _parse_lines_color_args( # Process **kwargs to handle aliases, conflicts with explicit kwargs: x_: np.ndarray y_: np.ndarray - x_, y_ = self._process_unit_info([("x", x), ("y", y)], kwargs) # ignore[union-attr] + x_, y_ = self._process_unit_info( + [("x", x), ("y", y)], kwargs + ) # type ignore[union-attr] # Handle z inputs: if z is not None: @@ -1982,17 +1992,17 @@ def _parse_lines_color_args( if plotnonfinite and colors is None: c = np.ma.masked_invalid(c) - x, y, s, edgecolors, linewidths = cbook._combine_masks( - x, y, s, edgecolors, linewidths - ) + x_, y_, s_, edgecolors, linewidths = cbook._combine_masks( + x_, y_, s_, edgecolors, linewidths + ) # type ignore[attr-defined] # non-public? else: - x, y, s, c, colors, edgecolors, linewidths = cbook._combine_masks( - x, y, s, c, colors, edgecolors, linewidths - ) + x_, y_, s_, c, colors, edgecolors, linewidths = cbook._combine_masks( + x_, y_, s_, c, colors, edgecolors, linewidths + ) # type ignore[attr-defined] # non-public? # Unmask edgecolors if it was actually a single RGB or RGBA. if ( - x.size in (3, 4) + x_.size in (3, 4) and np.ma.is_masked(edgecolors) and not np.ma.is_masked(orig_edgecolor) ): From 5626d736c955ba330d9552fa93e49065146fef2b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 23:35:16 +0000 Subject: [PATCH 053/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 8e5858c5972..f75d9b2d051 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,16 +1294,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1448,12 +1446,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1475,12 +1471,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1852,8 +1846,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1876,8 +1869,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From 98edb79eb01d7ea23f28d3181205669b72270b71 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 21 Mar 2024 00:44:03 +0100 Subject: [PATCH 054/102] Update utils.py --- xarray/plot/utils.py | 47 +++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index f75d9b2d051..8242ab0f149 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,14 +1294,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1448,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1475,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1846,7 +1852,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1869,7 +1876,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -1898,6 +1906,7 @@ def _line( This function helps the handling of datetimes since Linecollection doesn't support it directly, just like PatchCollection doesn't either. + The function attempts to be as similar to the scatter version as possible. """ import matplotlib.cbook as cbook import matplotlib.collections as mcoll @@ -1984,13 +1993,27 @@ def _parse_lines_color_args( if plotnonfinite and colors is None: c = np.ma.masked_invalid(c) - x_, y_, s_, edgecolors, linewidths = cbook._combine_masks( + ( + x_, + y_, + s_, + edgecolors, + linewidths, + ) = cbook._combine_masks( # type ignore[attr-defined] # non-public? x_, y_, s_, edgecolors, linewidths - ) # type ignore[attr-defined] # non-public? + ) else: - x_, y_, s_, c, colors, edgecolors, linewidths = cbook._combine_masks( + ( + x_, + y_, + s_, + c, + colors, + edgecolors, + linewidths, + ) = cbook._combine_masks( # type ignore[attr-defined] # non-public? x_, y_, s_, c, colors, edgecolors, linewidths - ) # type ignore[attr-defined] # non-public? + ) # Unmask edgecolors if it was actually a single RGB or RGBA. if ( From e90ef581dc255b8e383990030c5f9dd847cc4f03 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 23:44:38 +0000 Subject: [PATCH 055/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 8242ab0f149..90a7a389248 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,16 +1294,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1448,12 +1446,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1475,12 +1471,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1852,8 +1846,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1876,8 +1869,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From bee8b94fb06f84daddbff8fc901f898f912f7f4a Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 21 Mar 2024 22:25:14 +0100 Subject: [PATCH 056/102] Update utils.py --- xarray/plot/utils.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 90a7a389248..03c7020335c 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,14 +1294,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1448,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1475,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1846,7 +1852,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1869,7 +1876,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -1991,7 +1999,7 @@ def _parse_lines_color_args( s_, edgecolors, linewidths, - ) = cbook._combine_masks( # type ignore[attr-defined] # non-public? + ) = cbook._combine_masks( # type: ignore[attr-defined] # non-public? x_, y_, s_, edgecolors, linewidths ) else: @@ -2003,7 +2011,7 @@ def _parse_lines_color_args( colors, edgecolors, linewidths, - ) = cbook._combine_masks( # type ignore[attr-defined] # non-public? + ) = cbook._combine_masks( # type: ignore[attr-defined] # non-public? x_, y_, s_, c, colors, edgecolors, linewidths ) From 9f867cdcf1f944477b1dd3148bd18222fb98b9a6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:27:08 +0000 Subject: [PATCH 057/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 03c7020335c..b28600b0856 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,16 +1294,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1448,12 +1446,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1475,12 +1471,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1852,8 +1846,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1876,8 +1869,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From 1da316eee522cc9b54c64bd8e0299db18baea709 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 21 Mar 2024 22:46:21 +0100 Subject: [PATCH 058/102] Update utils.py --- xarray/plot/utils.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index b28600b0856..a31e634f947 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,14 +1294,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1448,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1475,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1846,7 +1852,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1869,7 +1876,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -2010,7 +2018,7 @@ def _parse_lines_color_args( # Unmask edgecolors if it was actually a single RGB or RGBA. if ( x_.size in (3, 4) - and np.ma.is_masked(edgecolors) + and isinstance(edgecolors, np.ma.MaskedArray) and not np.ma.is_masked(orig_edgecolor) ): edgecolors = edgecolors.data From e4aaaa808c63bdc448b9f0cf87953f8cd8eafd21 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:46:54 +0000 Subject: [PATCH 059/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index a31e634f947..0c286929809 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,16 +1294,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1448,12 +1446,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1475,12 +1471,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1852,8 +1846,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1876,8 +1869,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From fcad6ded798b2aacbff93ae5288a9e8291f3cf9a Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 22 Mar 2024 07:25:48 +0100 Subject: [PATCH 060/102] Update utils.py --- xarray/plot/utils.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 0c286929809..7422db4c5d2 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -30,7 +30,7 @@ from matplotlib.collections import LineCollection from matplotlib.colors import Colormap, Normalize from matplotlib.ticker import FuncFormatter - from matplotlib.typing import ColorType, LineStyleType + from matplotlib.typing import ColorType, DrawStyleType, LineStyleType from mpl_toolkits.mplot3d.art3d import Line3DCollection from numpy.typing import ArrayLike @@ -1294,14 +1294,16 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: ... +) -> None: + ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: ... +) -> pd.Series: + ... # copied from seaborn @@ -1446,10 +1448,12 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: + ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: ... + def _calc_widths(self, y: DataArray) -> DataArray: + ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1471,10 +1475,12 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: + ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: ... + def _indexes_centered(self, x: DataArray) -> DataArray: + ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1846,7 +1852,8 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: ... +) -> LineCollection: + ... @overload @@ -1868,8 +1875,10 @@ def _line( edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = ..., plotnonfinite: bool = ..., data=..., + drawstyle: DrawStyleType = ..., **kwargs, -) -> Line3DCollection: ... +) -> Line3DCollection: + ... def _line( @@ -1890,6 +1899,7 @@ def _line( edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, plotnonfinite: bool = False, data=None, + drawstyle: DrawStyleType = "default", **kwargs, ) -> LineCollection | Line3DCollection: """ @@ -2021,7 +2031,6 @@ def _parse_lines_color_args( if linestyle is None: linestyle = rcParams["lines.linestyle"] - drawstyle = kwargs.pop("drawstyle", "default") if drawstyle == "default": # Draw linear lines: xyz = list(v for v in (x_, y_, z) if v is not None) From 89820a0e892fa7f0c8464edca47871dcd8dbdd33 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 06:26:23 +0000 Subject: [PATCH 061/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 7422db4c5d2..5d08826b415 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1294,16 +1294,14 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): def _parse_size( data: None, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> None: - ... +) -> None: ... @overload def _parse_size( data: DataArray, norm: tuple[float | None, float | None, bool] | Normalize | None, -) -> pd.Series: - ... +) -> pd.Series: ... # copied from seaborn @@ -1448,12 +1446,10 @@ def data_is_numeric(self) -> bool: return self._data_is_numeric @overload - def _calc_widths(self, y: np.ndarray) -> np.ndarray: - ... + def _calc_widths(self, y: np.ndarray) -> np.ndarray: ... @overload - def _calc_widths(self, y: DataArray) -> DataArray: - ... + def _calc_widths(self, y: DataArray) -> DataArray: ... def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1475,12 +1471,10 @@ def _calc_widths(self, y: np.ndarray | DataArray) -> np.ndarray | DataArray: return widths @overload - def _indexes_centered(self, x: np.ndarray) -> np.ndarray: - ... + def _indexes_centered(self, x: np.ndarray) -> np.ndarray: ... @overload - def _indexes_centered(self, x: DataArray) -> DataArray: - ... + def _indexes_centered(self, x: DataArray) -> DataArray: ... def _indexes_centered(self, x: np.ndarray | DataArray) -> np.ndarray | DataArray: """ @@ -1852,8 +1846,7 @@ def _line( plotnonfinite: bool = ..., data=..., **kwargs, -) -> LineCollection: - ... +) -> LineCollection: ... @overload @@ -1877,8 +1870,7 @@ def _line( data=..., drawstyle: DrawStyleType = ..., **kwargs, -) -> Line3DCollection: - ... +) -> Line3DCollection: ... def _line( From 0106bb70a5ef1192dd0b49239db4db47d833e820 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 5 Apr 2024 22:50:51 +0200 Subject: [PATCH 062/102] Add some docs examples --- doc/user-guide/plotting.rst | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index 2bc049f1e2d..0cd08950e1f 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -847,6 +847,61 @@ And adding the z-axis For more advanced scatter plots, we recommend converting the relevant data variables to a pandas DataFrame and using the extensive plotting capabilities of ``seaborn``. +Lines +~~~~~~~ + +py:func:`xarray.plot.lines` calls matplotlib.collections.LineCollection under the hood, +allowing multiple lines being drawn efficiently. It uses similar arguments as +py:func:`xarray.plot.scatter`. + +Let's return to the air temperature dataset + +.. ipython:: python + :okwarning: + + airtemps = xr.tutorial.open_dataset("air_temperature") + air = airtemps.air - 273.15 + air.attrs = airtemps.air.attrs + air.attrs["units"] = "deg C" + + @savefig lines_air_hue.png + air.isel(lon=10).plot.lines(x="time", hue="lat") + +Make it a little more transparent + +.. ipython:: python + :okwarning: + + @savefig lines_air_hue_alpha.png + air.isel(lon=10).plot.lines(x="time", hue="lat", alpha=0.2) + +Zoom in a little on the xaxis, and compare a few latitudes and longitudes: + +.. ipython:: python + :okwarning: + air_zoom = air.isel(time=slice(1200, 1500), lat=[5, 10, 15], lon=[10, 15]) + air_zoom.plot.lines(x="time", hue="lat", linewidth="lon") + +Lines can modify the linestyle but does not allow markers. Instead combine lines +with scatter + +.. ipython:: python + :okwarning: + + @savefig lines_linestyle_marker.png + air.isel(lat=10, lon=10)[:200].plot.lines(x="time", color="k", linestyle="dashed") + air.isel(lat=10, lon=10)[:200].plot.scatter(x="time", color="k", marker="^") + +Switching to another dataset with more variables we can analyse in similar +fashion as scatter + +.. ipython:: python + :okwarning: + ds = xr.tutorial.scatter_example_dataset(seed=42) + + @savefig lines_xyzhuewidthrowcol.png + ds.plot.lines(x="A", y="B", z="z", hue="y", linewidth="x", row="x", col="w") + Quiver ~~~~~~ From f08f8c54f924235286227e7769d6554fbc3ba730 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 20:51:42 +0000 Subject: [PATCH 063/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/user-guide/plotting.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index 0cd08950e1f..113deba1862 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -879,6 +879,7 @@ Zoom in a little on the xaxis, and compare a few latitudes and longitudes: .. ipython:: python :okwarning: + air_zoom = air.isel(time=slice(1200, 1500), lat=[5, 10, 15], lon=[10, 15]) air_zoom.plot.lines(x="time", hue="lat", linewidth="lon") @@ -897,6 +898,7 @@ fashion as scatter .. ipython:: python :okwarning: + ds = xr.tutorial.scatter_example_dataset(seed=42) @savefig lines_xyzhuewidthrowcol.png From d57b753545f1aad360a67d2297c401ce052a85e6 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:01:41 +0200 Subject: [PATCH 064/102] Update plotting.rst --- doc/user-guide/plotting.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index 0cd08950e1f..c6f8b7b88e7 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -899,8 +899,8 @@ fashion as scatter :okwarning: ds = xr.tutorial.scatter_example_dataset(seed=42) - @savefig lines_xyzhuewidthrowcol.png - ds.plot.lines(x="A", y="B", z="z", hue="y", linewidth="x", row="x", col="w") + @savefig lines_xyhuewidthrowcol.png + ds.plot.lines(x="A", y="B", hue="y", linewidth="x", row="x", col="w") Quiver ~~~~~~ From 532cb9dbe01b177ce60421327afed8f1bf96d977 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:49:59 +0200 Subject: [PATCH 065/102] Update plotting.rst --- doc/user-guide/plotting.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index 90266d9a569..dc705c380c1 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -57,6 +57,8 @@ Imports # Use defaults so we don't get gridlines in generated docs import matplotlib as mpl + %matplotlib inline + mpl.rcdefaults() The following imports are necessary for all of the examples. @@ -848,7 +850,7 @@ For more advanced scatter plots, we recommend converting the relevant data varia to a pandas DataFrame and using the extensive plotting capabilities of ``seaborn``. Lines -~~~~~~~ +~~~~~ py:func:`xarray.plot.lines` calls matplotlib.collections.LineCollection under the hood, allowing multiple lines being drawn efficiently. It uses similar arguments as @@ -881,6 +883,8 @@ Zoom in a little on the xaxis, and compare a few latitudes and longitudes: :okwarning: air_zoom = air.isel(time=slice(1200, 1500), lat=[5, 10, 15], lon=[10, 15]) + + @savefig lines_hue_linewidth.png air_zoom.plot.lines(x="time", hue="lat", linewidth="lon") Lines can modify the linestyle but does not allow markers. Instead combine lines From 50cd419a16f479b74704c3c7ade98f52cbd389c4 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:59:14 +0200 Subject: [PATCH 066/102] Update plotting.rst --- doc/user-guide/plotting.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index dc705c380c1..f2c8a70274f 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -57,8 +57,6 @@ Imports # Use defaults so we don't get gridlines in generated docs import matplotlib as mpl - %matplotlib inline - mpl.rcdefaults() The following imports are necessary for all of the examples. From cc14075390604c1d285fed642d1317179e99d86b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:28:48 +0200 Subject: [PATCH 067/102] Update plotting.rst --- doc/user-guide/plotting.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index f2c8a70274f..691b074890c 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -883,7 +883,7 @@ Zoom in a little on the xaxis, and compare a few latitudes and longitudes: air_zoom = air.isel(time=slice(1200, 1500), lat=[5, 10, 15], lon=[10, 15]) @savefig lines_hue_linewidth.png - air_zoom.plot.lines(x="time", hue="lat", linewidth="lon") + air_zoom.plot.lines(x="time", hue="lat", linewidth="lon", add_colorbar=False) Lines can modify the linestyle but does not allow markers. Instead combine lines with scatter @@ -891,8 +891,8 @@ with scatter .. ipython:: python :okwarning: - @savefig lines_linestyle_marker.png air.isel(lat=10, lon=10)[:200].plot.lines(x="time", color="k", linestyle="dashed") + @savefig lines_linestyle_marker.png air.isel(lat=10, lon=10)[:200].plot.scatter(x="time", color="k", marker="^") Switching to another dataset with more variables we can analyse in similar From 59267ad2c5206db80ada99fea94ef3d6190844d1 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 12:02:15 +0200 Subject: [PATCH 068/102] Update plotting.rst --- doc/user-guide/plotting.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index 691b074890c..b6642a89581 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -850,6 +850,11 @@ to a pandas DataFrame and using the extensive plotting capabilities of ``seaborn Lines ~~~~~ +.. ipython:: python + :suppress: + + plt.close("all") + py:func:`xarray.plot.lines` calls matplotlib.collections.LineCollection under the hood, allowing multiple lines being drawn efficiently. It uses similar arguments as py:func:`xarray.plot.scatter`. @@ -892,8 +897,10 @@ with scatter :okwarning: air.isel(lat=10, lon=10)[:200].plot.lines(x="time", color="k", linestyle="dashed") - @savefig lines_linestyle_marker.png air.isel(lat=10, lon=10)[:200].plot.scatter(x="time", color="k", marker="^") + @savefig lines_linestyle_marker.png + plt.draw() + Switching to another dataset with more variables we can analyse in similar fashion as scatter From 1720e0b59a72e26a59b96b7116dbe8ffea1469a1 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 12:02:41 +0200 Subject: [PATCH 069/102] Update plotting.rst --- doc/user-guide/plotting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index b6642a89581..dfd652aa0f7 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -878,7 +878,7 @@ Make it a little more transparent :okwarning: @savefig lines_air_hue_alpha.png - air.isel(lon=10).plot.lines(x="time", hue="lat", alpha=0.2) + air.isel(lon=10).plot.lines(x="time", hue="lat", alpha=0.25) Zoom in a little on the xaxis, and compare a few latitudes and longitudes: From d45c819db9214aef765d6a8ca348e06dbe6346b7 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 15:51:33 +0200 Subject: [PATCH 070/102] Update plotting.rst --- doc/user-guide/plotting.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/doc/user-guide/plotting.rst b/doc/user-guide/plotting.rst index dfd652aa0f7..ebe9fd3b561 100644 --- a/doc/user-guide/plotting.rst +++ b/doc/user-guide/plotting.rst @@ -855,11 +855,11 @@ Lines plt.close("all") -py:func:`xarray.plot.lines` calls matplotlib.collections.LineCollection under the hood, +:py:func:`xarray.plot.lines` calls matplotlib.collections.LineCollection under the hood, allowing multiple lines being drawn efficiently. It uses similar arguments as -py:func:`xarray.plot.scatter`. +:py:func:`xarray.plot.scatter`. -Let's return to the air temperature dataset +Let's return to the air temperature dataset: .. ipython:: python :okwarning: @@ -872,15 +872,18 @@ Let's return to the air temperature dataset @savefig lines_air_hue.png air.isel(lon=10).plot.lines(x="time", hue="lat") -Make it a little more transparent +Make it a little more transparent: .. ipython:: python :okwarning: @savefig lines_air_hue_alpha.png - air.isel(lon=10).plot.lines(x="time", hue="lat", alpha=0.25) + air.isel(lon=10).plot.lines(x="time", hue="lat", alpha=0.2) -Zoom in a little on the xaxis, and compare a few latitudes and longitudes: +Zoom in a little on the x-axis, and compare a few latitudes and longitudes, +group them using ``hue`` and ``linewidth``. The ``linewidth`` kwarg works in +a similar way as ``markersize`` kwarg for scatter plots, it lets you vary the +line's size by variable value. .. ipython:: python :okwarning: @@ -890,8 +893,8 @@ Zoom in a little on the xaxis, and compare a few latitudes and longitudes: @savefig lines_hue_linewidth.png air_zoom.plot.lines(x="time", hue="lat", linewidth="lon", add_colorbar=False) -Lines can modify the linestyle but does not allow markers. Instead combine lines -with scatter +Lines can modify the linestyle but does not allow markers. Instead combine :py:func:`xarray.plot.lines` +with :py:func:`xarray.plot.scatter`: .. ipython:: python :okwarning: @@ -903,7 +906,7 @@ with scatter Switching to another dataset with more variables we can analyse in similar -fashion as scatter +fashion as :py:func:`xarray.plot.scatter`: .. ipython:: python :okwarning: From 9f1154a32e60b687ff109319e357673d1644ef1e Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 15:53:42 +0200 Subject: [PATCH 071/102] Update api.rst --- doc/api.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/api.rst b/doc/api.rst index a8f8ea7dd1c..65d8ca6f52b 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -684,6 +684,7 @@ Dataset :template: autosummary/accessor_method.rst Dataset.plot.scatter + Dataset.plot.lines Dataset.plot.quiver Dataset.plot.streamplot @@ -708,6 +709,7 @@ DataArray DataArray.plot.pcolormesh DataArray.plot.step DataArray.plot.scatter + DataArray.plot.lines DataArray.plot.surface From 659a9fe385545e9720104a5016a680776cf6986a Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:40:42 +0200 Subject: [PATCH 072/102] improve docs --- xarray/plot/__init__.py | 2 ++ xarray/plot/dataarray_plot.py | 6 ++++-- xarray/plot/dataset_plot.py | 7 ++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/xarray/plot/__init__.py b/xarray/plot/__init__.py index ae7a0012b32..c995dee9ab9 100644 --- a/xarray/plot/__init__.py +++ b/xarray/plot/__init__.py @@ -13,6 +13,7 @@ hist, imshow, line, + lines, pcolormesh, plot, step, @@ -32,5 +33,6 @@ "pcolormesh", "FacetGrid", "scatter", + "lines" "surface", ] diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 70aecf95093..25ba02729e8 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1249,8 +1249,10 @@ def lines( **kwargs, ) -> LineCollection: """ - Line plot of DataArray index against values - Wraps :func:`matplotlib:matplotlib.collections.LineCollection` + Line plot of DataArray values. + + Wraps :func:`matplotlib:matplotlib.collections.LineCollection` which allows + efficient plotting of many lines. """ if "u" in kwargs or "v" in kwargs: raise ValueError("u, v are not allowed in lines plots.") diff --git a/xarray/plot/dataset_plot.py b/xarray/plot/dataset_plot.py index f588d4e67dc..295385efb26 100644 --- a/xarray/plot/dataset_plot.py +++ b/xarray/plot/dataset_plot.py @@ -1075,7 +1075,12 @@ def lines( levels: ArrayLike | None = None, **kwargs: Any, ) -> LineCollection | FacetGrid[DataArray]: - """Line plot Dataset data variables against each other.""" + """ + Line plot Dataset data variables against each other. + + Wraps :func:`matplotlib:matplotlib.collections.LineCollection` which allows + efficient plotting of many lines. + """ locals_ = locals() del locals_["ds"] locals_.update(locals_.pop("kwargs", {})) From 8009145c5352b3d29aa64042183f421efdb14f16 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 6 Apr 2024 14:41:15 +0000 Subject: [PATCH 073/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xarray/plot/__init__.py b/xarray/plot/__init__.py index c995dee9ab9..89ab2bb9487 100644 --- a/xarray/plot/__init__.py +++ b/xarray/plot/__init__.py @@ -33,6 +33,5 @@ "pcolormesh", "FacetGrid", "scatter", - "lines" - "surface", + "lines" "surface", ] From 78e26cb51dfd078ce59e25a16b1263b6d5d1ef94 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:42:24 +0200 Subject: [PATCH 074/102] Update __init__.py --- xarray/plot/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/__init__.py b/xarray/plot/__init__.py index c995dee9ab9..8016e34274a 100644 --- a/xarray/plot/__init__.py +++ b/xarray/plot/__init__.py @@ -33,6 +33,6 @@ "pcolormesh", "FacetGrid", "scatter", - "lines" + "lines", "surface", ] From f4c3c43a2153cdc69368a87fcdf5746965a0367b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:42:22 +0200 Subject: [PATCH 075/102] fix legend values --- xarray/plot/utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 9b376d19d82..d90c404dffe 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1722,9 +1722,8 @@ def _add_legend( lbl += lbl_ # Only save unique values: - u, ind = np.unique(lbl, return_index=True) - ind = np.argsort(ind) - lbl = u[ind].tolist() + lbl, ind = np.unique(lbl, return_index=True) + lbl = lbl.tolist() hdl = np.array(hdl)[ind].tolist() # Add a subtitle: From bc433abfd39868d1afda13c872d8a72c7859b8c4 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:42:26 +0200 Subject: [PATCH 076/102] Update api-hidden.rst --- doc/api-hidden.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api-hidden.rst b/doc/api-hidden.rst index d9c89649358..ebefed87d52 100644 --- a/doc/api-hidden.rst +++ b/doc/api-hidden.rst @@ -391,6 +391,7 @@ plot.imshow plot.pcolormesh plot.scatter + plot.lines plot.surface CFTimeIndex.all From 08965feca61cf77549c0e0d591e4616fc02a43a6 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:47:12 +0200 Subject: [PATCH 077/102] Update utils.py --- xarray/plot/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index d90c404dffe..6109f004e62 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1722,7 +1722,7 @@ def _add_legend( lbl += lbl_ # Only save unique values: - lbl, ind = np.unique(lbl, return_index=True) + lbl, ind = np.unique(np.array(lbl), return_index=True) lbl = lbl.tolist() hdl = np.array(hdl)[ind].tolist() From 8b3558a25540931906aecd40c90db27f6034a707 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:48:53 +0200 Subject: [PATCH 078/102] Add more legend labels tests --- xarray/tests/test_plot.py | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index e041c9ce266..7f4cf8fa867 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -2897,6 +2897,57 @@ def test_legend_labels_facetgrid(self) -> None: ) assert actual == expected + def test_legend_labels_facegrid2(self) -> None: + ds = xr.tutorial.scatter_example_dataset(seed=42) + + g = ds.plot.scatter( + x="A", y="B", hue="y", markersize="x", row="x", col="w", add_colorbar=False + ) + + legend = g.figlegend + assert legend is not None + actual = tuple(t.get_text() for t in legend.texts) + expected = ( + "y [yunits]", + "$\\mathdefault{0.0}$", + "$\\mathdefault{0.1}$", + "$\\mathdefault{0.2}$", + "$\\mathdefault{0.3}$", + "$\\mathdefault{0.4}$", + "$\\mathdefault{0.5}$", + "$\\mathdefault{0.6}$", + "$\\mathdefault{0.7}$", + "$\\mathdefault{0.8}$", + "$\\mathdefault{0.9}$", + "$\\mathdefault{1.0}$", + "x [xunits]", + "$\\mathdefault{0}$", + "$\\mathdefault{1}$", + "$\\mathdefault{2}$", + ) + assert actual == expected + + actual = [v.get_markersize() for v in legend.get_lines()] + expected = [ + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 4.242640687119285, + 6.708203932499369, + 8.48528137423857, + ] + np.testing.assert_allclose(expected, actual) + def test_add_legend_by_default(self) -> None: sc = self.ds.plot.scatter(x="A", y="B", hue="hue") fig = sc.figure From 7f1780f0670307941e686e846314ec571b562826 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:49:04 +0200 Subject: [PATCH 079/102] Try without fix --- xarray/plot/utils.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 6109f004e62..6ab6b508f8d 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -31,6 +31,7 @@ from matplotlib.colors import Colormap, Normalize from matplotlib.ticker import FuncFormatter from matplotlib.typing import ColorType, DrawStyleType, LineStyleType + from matplotlib.lines import Line2D from mpl_toolkits.mplot3d.art3d import Line3DCollection from numpy.typing import ArrayLike @@ -1715,15 +1716,24 @@ def _add_legend( # values correctly. Order might be different because # legend_elements uses np.unique instead of pd.unique, # FacetGrid.add_legend might have troubles with this: - hdl, lbl = [], [] + hdl: list[Line2D] = [] + lbl: list[str] = [] for p in primitive: hdl_, lbl_ = legend_elements(p, prop, num="auto", func=huesizeplt.func) hdl += hdl_ lbl += lbl_ - # Only save unique values: - lbl, ind = np.unique(np.array(lbl), return_index=True) - lbl = lbl.tolist() + # Only save unique values, don't sort values as it was already sort in + # legend_elements: + # lbl_ = np.array(lbl) + # _, ind = np.unique(lbl_, return_index=True) + # ind = np.sort(ind) + # lbl = lbl_[ind].tolist() + # hdl = np.array(hdl)[ind].tolist() + + u, ind = np.unique(lbl, return_index=True) + ind = np.argsort(ind) + lbl = u[ind].tolist() hdl = np.array(hdl)[ind].tolist() # Add a subtitle: From 8a495b839b21bfdd5ea7d7db7e1c666f7a3c2f21 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:49:37 +0000 Subject: [PATCH 080/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 6ab6b508f8d..fb132271fac 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -29,9 +29,9 @@ from matplotlib.axes import Axes from matplotlib.collections import LineCollection from matplotlib.colors import Colormap, Normalize + from matplotlib.lines import Line2D from matplotlib.ticker import FuncFormatter from matplotlib.typing import ColorType, DrawStyleType, LineStyleType - from matplotlib.lines import Line2D from mpl_toolkits.mplot3d.art3d import Line3DCollection from numpy.typing import ArrayLike From 7684c659ceca32c1dc1a6fc5997b9ac4d0765581 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:59:48 +0200 Subject: [PATCH 081/102] add fix --- xarray/plot/utils.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index fb132271fac..bafad53d8ea 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1725,17 +1725,17 @@ def _add_legend( # Only save unique values, don't sort values as it was already sort in # legend_elements: - # lbl_ = np.array(lbl) - # _, ind = np.unique(lbl_, return_index=True) - # ind = np.sort(ind) - # lbl = lbl_[ind].tolist() - # hdl = np.array(hdl)[ind].tolist() - - u, ind = np.unique(lbl, return_index=True) - ind = np.argsort(ind) - lbl = u[ind].tolist() + lbl_ = np.array(lbl) + _, ind = np.unique(lbl_, return_index=True) + ind = np.sort(ind) + lbl = lbl_[ind].tolist() hdl = np.array(hdl)[ind].tolist() + # u, ind = np.unique(lbl, return_index=True) + # ind = np.argsort(ind) + # lbl = u[ind].tolist() + # hdl = np.array(hdl)[ind].tolist() + # Add a subtitle: hdl, lbl = _legend_add_subtitle(hdl, lbl, label_from_attrs(huesizeplt.data)) handles += hdl From 971fb2e40ef8319574889515140277d48c9c6a69 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:00:01 +0200 Subject: [PATCH 082/102] mypy fixes --- xarray/tests/test_plot.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 7f4cf8fa867..adea11e1671 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -2906,8 +2906,8 @@ def test_legend_labels_facegrid2(self) -> None: legend = g.figlegend assert legend is not None - actual = tuple(t.get_text() for t in legend.texts) - expected = ( + actual_text = [t.get_text() for t in legend.texts] + expected_text = [ "y [yunits]", "$\\mathdefault{0.0}$", "$\\mathdefault{0.1}$", @@ -2924,11 +2924,11 @@ def test_legend_labels_facegrid2(self) -> None: "$\\mathdefault{0}$", "$\\mathdefault{1}$", "$\\mathdefault{2}$", - ) - assert actual == expected + ] + assert actual_text == expected_text - actual = [v.get_markersize() for v in legend.get_lines()] - expected = [ + actual_size = [v.get_markersize() for v in legend.get_lines()] + expected_size = [ 6.0, 6.0, 6.0, @@ -2946,7 +2946,7 @@ def test_legend_labels_facegrid2(self) -> None: 6.708203932499369, 8.48528137423857, ] - np.testing.assert_allclose(expected, actual) + np.testing.assert_allclose(expected_size, actual_size) def test_add_legend_by_default(self) -> None: sc = self.ds.plot.scatter(x="A", y="B", hue="hue") From c47b1ad5787b95bd4e1af1af8621aa6b46b9ed4f Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 11:10:50 +0200 Subject: [PATCH 083/102] Make sure lines legend is correct --- xarray/plot/utils.py | 6 ++--- xarray/tests/test_plot.py | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index bafad53d8ea..6420ea5ca79 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1056,9 +1056,9 @@ def _get_color_and_size(value): elif prop == "sizes": if isinstance(self, mpl.collections.LineCollection): - arr = self.get_linewidths() + arr = np.ma.asarray(self.get_linewidths()) else: - arr = self.get_sizes() + arr = np.ma.asarray(self.get_sizes()) _color = kwargs.pop("color", "k") def _get_color_and_size(value): @@ -1071,7 +1071,7 @@ def _get_color_and_size(value): ) # Get the unique values and their labels: - values = np.unique(arr) + values = np.unique(arr[~arr.mask]) label_values = np.asarray(func(values)) label_values_are_numeric = np.issubdtype(label_values.dtype, np.number) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index adea11e1671..2e6ee93056f 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3513,3 +3513,57 @@ def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> Non expected_linestyle = [_scale_dashes(*_get_dash_pattern(linestyle), w)] actual_linestyle = coll.get_linestyle() assert expected_linestyle == actual_linestyle + + +@requires_matplotlib +def test_plot1d_lines_legend() -> None: + # asserts that order is correct, only unique values, no nans/masked values. + + ds = xr.tutorial.scatter_example_dataset(seed=42) + g = ds.plot.lines( + x="A", y="B", hue="y", linewidth="x", row="x", col="w", add_colorbar=False + ) + + legend = g.figlegend + assert legend is not None + actual = tuple(t.get_text() for t in legend.texts) + expected = ( + "y [yunits]", + "$\\mathdefault{0.0}$", + "$\\mathdefault{0.1}$", + "$\\mathdefault{0.2}$", + "$\\mathdefault{0.3}$", + "$\\mathdefault{0.4}$", + "$\\mathdefault{0.5}$", + "$\\mathdefault{0.6}$", + "$\\mathdefault{0.7}$", + "$\\mathdefault{0.8}$", + "$\\mathdefault{0.9}$", + "$\\mathdefault{1.0}$", + "x [xunits]", + "$\\mathdefault{0}$", + "$\\mathdefault{1}$", + "$\\mathdefault{2}$", + ) + assert actual == expected + + actual = [v.get_linewidth() for v in legend.get_lines()] + expected = [ + 1.5, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 1.5, + 1.224744871391589, + 1.9364916731037085, + 2.449489742783178, + ] + np.testing.assert_allclose(expected, actual) From 30213b2b213dad3e0cb5189902d196a678723dfb Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 11:24:25 +0200 Subject: [PATCH 084/102] Update test_plot.py --- xarray/tests/test_plot.py | 96 ++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 2e6ee93056f..220d184c2a8 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3516,54 +3516,56 @@ def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> Non @requires_matplotlib -def test_plot1d_lines_legend() -> None: +def test_plot1d_lines_facetgrid_legend() -> None: # asserts that order is correct, only unique values, no nans/masked values. ds = xr.tutorial.scatter_example_dataset(seed=42) - g = ds.plot.lines( - x="A", y="B", hue="y", linewidth="x", row="x", col="w", add_colorbar=False - ) - legend = g.figlegend - assert legend is not None - actual = tuple(t.get_text() for t in legend.texts) - expected = ( - "y [yunits]", - "$\\mathdefault{0.0}$", - "$\\mathdefault{0.1}$", - "$\\mathdefault{0.2}$", - "$\\mathdefault{0.3}$", - "$\\mathdefault{0.4}$", - "$\\mathdefault{0.5}$", - "$\\mathdefault{0.6}$", - "$\\mathdefault{0.7}$", - "$\\mathdefault{0.8}$", - "$\\mathdefault{0.9}$", - "$\\mathdefault{1.0}$", - "x [xunits]", - "$\\mathdefault{0}$", - "$\\mathdefault{1}$", - "$\\mathdefault{2}$", - ) - assert actual == expected - - actual = [v.get_linewidth() for v in legend.get_lines()] - expected = [ - 1.5, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 6.0, - 1.5, - 1.224744871391589, - 1.9364916731037085, - 2.449489742783178, - ] - np.testing.assert_allclose(expected, actual) + with figure_context(): + g = ds.plot.lines( + x="A", y="B", hue="y", linewidth="x", row="x", col="w", add_colorbar=False + ) + + legend = g.figlegend + assert legend is not None + actual = tuple(t.get_text() for t in legend.texts) + expected = ( + "y [yunits]", + "$\\mathdefault{0.0}$", + "$\\mathdefault{0.1}$", + "$\\mathdefault{0.2}$", + "$\\mathdefault{0.3}$", + "$\\mathdefault{0.4}$", + "$\\mathdefault{0.5}$", + "$\\mathdefault{0.6}$", + "$\\mathdefault{0.7}$", + "$\\mathdefault{0.8}$", + "$\\mathdefault{0.9}$", + "$\\mathdefault{1.0}$", + "x [xunits]", + "$\\mathdefault{0}$", + "$\\mathdefault{1}$", + "$\\mathdefault{2}$", + ) + assert actual == expected + + actual = [v.get_linewidth() for v in legend.get_lines()] + expected = [ + 1.5, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 6.0, + 1.5, + 1.224744871391589, + 1.9364916731037085, + 2.449489742783178, + ] + np.testing.assert_allclose(expected, actual) From 2bf943d39b64023dc8dff80f62574c399f0c81a5 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 11:29:32 +0200 Subject: [PATCH 085/102] Update test_plot.py --- xarray/tests/test_plot.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 220d184c2a8..7a9e96a510c 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3528,8 +3528,8 @@ def test_plot1d_lines_facetgrid_legend() -> None: legend = g.figlegend assert legend is not None - actual = tuple(t.get_text() for t in legend.texts) - expected = ( + actual_text = [t.get_text() for t in legend.texts] + expected_text = [ "y [yunits]", "$\\mathdefault{0.0}$", "$\\mathdefault{0.1}$", @@ -3546,11 +3546,11 @@ def test_plot1d_lines_facetgrid_legend() -> None: "$\\mathdefault{0}$", "$\\mathdefault{1}$", "$\\mathdefault{2}$", - ) - assert actual == expected + ] + assert expected_text == actual_text - actual = [v.get_linewidth() for v in legend.get_lines()] - expected = [ + actual_size = [v.get_linewidth() for v in legend.get_lines()] + expected_size = [ 1.5, 6.0, 6.0, @@ -3568,4 +3568,4 @@ def test_plot1d_lines_facetgrid_legend() -> None: 1.9364916731037085, 2.449489742783178, ] - np.testing.assert_allclose(expected, actual) + np.testing.assert_allclose(expected_size, actual_size) From 422b8da93d7787ee3250233f5ca5796059990a4c Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 11:52:33 +0200 Subject: [PATCH 086/102] Update test_plot.py --- xarray/tests/test_plot.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 7a9e96a510c..4ca54be5819 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3319,7 +3319,7 @@ def test_maybe_gca() -> None: @requires_matplotlib @pytest.mark.parametrize("plotfunc", ["scatter", "lines"]) @pytest.mark.parametrize( - "x, y, z, hue, markersize, row, col, add_legend, add_colorbar", + "x, y, z, hue, _size, row, col, add_legend, add_colorbar", [ ("A", "B", None, None, None, None, None, None, None), ("B", "A", None, "w", None, None, None, True, None), @@ -3328,6 +3328,7 @@ def test_maybe_gca() -> None: ("B", "A", "z", "w", None, None, None, True, None), ("A", "B", "z", "y", "x", None, None, True, True), ("A", "B", "z", "y", "x", "w", None, True, True), + ("A", "B", "z", "y", "x", "w", "x", True, True), ], ) def test_plot1d_functions( @@ -3335,7 +3336,7 @@ def test_plot1d_functions( y: Hashable, z: Hashable, hue: Hashable, - markersize: Hashable, + _size: Hashable, row: Hashable, col: Hashable, add_legend: bool | None, @@ -3345,7 +3346,7 @@ def test_plot1d_functions( """Test plot1d function. Merge with TestPlot1D eventually.""" ds = xr.tutorial.scatter_example_dataset() - extra_coords = [v for v in [x, hue, markersize] if v is not None] + extra_coords = [v for v in [x, hue, _size] if v is not None] # Base coords: coords = dict(ds.coords) @@ -3360,7 +3361,7 @@ def test_plot1d_functions( x=x, z=z, hue=hue, - markersize=markersize, + _size=_size, add_legend=add_legend, add_colorbar=add_colorbar, ) From 0b16cf91a0d5bfdbf5d2d51ee3ccbf5e649a3875 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 12:20:16 +0200 Subject: [PATCH 087/102] Update test_plot.py --- xarray/tests/test_plot.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 4ca54be5819..6bb37674a34 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3344,24 +3344,30 @@ def test_plot1d_functions( plotfunc: str, ) -> None: """Test plot1d function. Merge with TestPlot1D eventually.""" - ds = xr.tutorial.scatter_example_dataset() + import matplotlib.pyplot as plt + + ds = xr.tutorial.scatter_example_dataset(seed=42) - extra_coords = [v for v in [x, hue, _size] if v is not None] + # extra_coords = [v for v in [x, hue, _size] if v is not None] - # Base coords: - coords = dict(ds.coords) + # # Base coords: + # coords = dict(ds.coords) - # Add extra coords to the DataArray: - coords.update({v: ds[v] for v in extra_coords}) + # # Add extra coords to the DataArray: + # coords.update({v: ds[v] for v in extra_coords}) - darray = xr.DataArray(ds[y], coords=coords) + # darray = xr.DataArray(ds[y], coords=coords) with figure_context(): - getattr(darray.plot, plotfunc)( + # plt.close("all") + getattr(ds.plot, plotfunc)( x=x, + y=y, z=z, hue=hue, _size=_size, + row=row, + col=col, add_legend=add_legend, add_colorbar=add_colorbar, ) From 6e13194e0ff5f6925d2b5c6cdb98fd94e82929a4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 10:21:04 +0000 Subject: [PATCH 088/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/tests/test_plot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 6bb37674a34..083accbe8db 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3344,7 +3344,6 @@ def test_plot1d_functions( plotfunc: str, ) -> None: """Test plot1d function. Merge with TestPlot1D eventually.""" - import matplotlib.pyplot as plt ds = xr.tutorial.scatter_example_dataset(seed=42) From c26233e09aac356b4dab7fdeb73caef4c23a2a7b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 12:38:10 +0200 Subject: [PATCH 089/102] Update facetgrid.py --- xarray/plot/facetgrid.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/xarray/plot/facetgrid.py b/xarray/plot/facetgrid.py index faf809a8a74..f04092256c4 100644 --- a/xarray/plot/facetgrid.py +++ b/xarray/plot/facetgrid.py @@ -477,7 +477,7 @@ def map_plot1d( func_kwargs["add_title"] = False add_labels_ = np.zeros(self.axs.shape + (3,), dtype=bool) - if kwargs.get("z") is not None: + if coords_to_plot["z"] is not None: # 3d plots looks better with all labels. 3d plots can't sharex either so it # is easy to get lost while rotating the plots: add_labels_[:] = True @@ -490,10 +490,10 @@ def map_plot1d( # Set up the lists of names for the row and column facet variables: if self._single_group: full = tuple( - {self._single_group: x} - for x in range(0, self.data[self._single_group].size) + {self._single_group: v} + for v in range(0, self.data[self._single_group].size) ) - empty = tuple(None for x in range(self._nrow * self._ncol - len(full))) + empty = (None,) * (self._nrow * self._ncol - len(full)) name_d = full + empty else: rowcols = itertools.product( @@ -513,8 +513,9 @@ def map_plot1d( subset = self.data.isel(d) mappable = func( subset, - x=x, - y=y, + x=coords_to_plot["x"], + y=coords_to_plot["y"], + z=coords_to_plot["z"], ax=ax, hue=hue, _size=size_, From 10fac373dd3b45cc3a325d081861240e0175fe5d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 12:45:19 +0200 Subject: [PATCH 090/102] Update facetgrid.py --- xarray/plot/facetgrid.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/plot/facetgrid.py b/xarray/plot/facetgrid.py index f04092256c4..68edb58bd32 100644 --- a/xarray/plot/facetgrid.py +++ b/xarray/plot/facetgrid.py @@ -514,7 +514,6 @@ def map_plot1d( mappable = func( subset, x=coords_to_plot["x"], - y=coords_to_plot["y"], z=coords_to_plot["z"], ax=ax, hue=hue, From a83b3be37fceb20525f7a01def32ed097bd412ef Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 7 Apr 2024 22:26:39 +0200 Subject: [PATCH 091/102] Update dataarray_plot.py --- xarray/plot/dataarray_plot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 25ba02729e8..641bd9a067c 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -191,7 +191,7 @@ def _prepare_plot1d_data( # this can be solved by adding a nan element in between the flattening # points: dims_T: list[Hashable] = [] - if np.issubdtype(darray.dtype, np.floating): + if plotfunc_name == "lines" and np.issubdtype(darray.dtype, np.floating): i = 0 for v in ("z", "x"): coord = coords_to_plot.get(v, None) @@ -211,7 +211,7 @@ def _prepare_plot1d_data( darray_nan = np.nan * darray.isel({d: -1}) darray = concat([darray, darray_nan], dim=d) dims_T.append(d) - i += 1 + # i += 1 # Lines should never connect to the same coordinate when stacked, # transpose to avoid this as much as possible: From c3f461cbbdf5b10407833288a4f0fa11bb5be9c6 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 17 May 2024 21:47:21 +0200 Subject: [PATCH 092/102] remove commented code --- xarray/plot/utils.py | 5 ----- xarray/tests/test_plot.py | 12 ------------ 2 files changed, 17 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 6420ea5ca79..0d2e6272fb3 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1731,11 +1731,6 @@ def _add_legend( lbl = lbl_[ind].tolist() hdl = np.array(hdl)[ind].tolist() - # u, ind = np.unique(lbl, return_index=True) - # ind = np.argsort(ind) - # lbl = u[ind].tolist() - # hdl = np.array(hdl)[ind].tolist() - # Add a subtitle: hdl, lbl = _legend_add_subtitle(hdl, lbl, label_from_attrs(huesizeplt.data)) handles += hdl diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 083accbe8db..23e1964f012 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3344,21 +3344,9 @@ def test_plot1d_functions( plotfunc: str, ) -> None: """Test plot1d function. Merge with TestPlot1D eventually.""" - ds = xr.tutorial.scatter_example_dataset(seed=42) - # extra_coords = [v for v in [x, hue, _size] if v is not None] - - # # Base coords: - # coords = dict(ds.coords) - - # # Add extra coords to the DataArray: - # coords.update({v: ds[v] for v in extra_coords}) - - # darray = xr.DataArray(ds[y], coords=coords) - with figure_context(): - # plt.close("all") getattr(ds.plot, plotfunc)( x=x, y=y, From 30e235609aa5c8caefab19cf231ea37fbdddcfea Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 28 May 2024 21:59:27 +0200 Subject: [PATCH 093/102] Update xarray/plot/utils.py --- xarray/plot/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 0d2e6272fb3..fc98ffacf45 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -2021,7 +2021,6 @@ def _parse_lines_color_args( ): edgecolors = edgecolors.data - # scales = s # Renamed for readability below. # load default linestyle from rcParams if linestyle is None: From 47956b48c08d3f746d9eb3a57c0791af12277deb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 20:00:03 +0000 Subject: [PATCH 094/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index fc98ffacf45..f8d1e3996ee 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -2021,7 +2021,6 @@ def _parse_lines_color_args( ): edgecolors = edgecolors.data - # load default linestyle from rcParams if linestyle is None: linestyle = rcParams["lines.linestyle"] From f53da04152aac0b1a64ff1c84580c9fa2317800e Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 23 Jun 2024 22:36:37 +0200 Subject: [PATCH 095/102] Update whats-new.rst --- doc/whats-new.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 51a2c98fb9c..ad69bb3dfa8 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -24,6 +24,10 @@ New Features ~~~~~~~~~~~~ - Allow chunking for arrays with duplicated dimension names (:issue:`8759`, :pull:`9099`). By `Martin Raspaud `_. +- Added new plot method `lines` which allows creating line plots efficiently in + a similiar manner to `scatter`. (:pull:`7173`) + By `Jimmy Westling `_. + Breaking changes ~~~~~~~~~~~~~~~~ From 0a204025133f0ebf627e6f5c7ec8be75935a60b7 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 23 Jun 2024 22:41:51 +0200 Subject: [PATCH 096/102] Add more docs --- xarray/plot/dataarray_plot.py | 7 ++++++- xarray/plot/dataset_plot.py | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 641bd9a067c..d2fad56fbf4 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -486,6 +486,10 @@ def line( primitive : list of Line3D or FacetGrid When either col or row is given, returns a FacetGrid, otherwise a list of matplotlib Line3D objects. + + See also + -------- + Use :py:func:`xarray.plot.lines` for efficient plotting of many lines. """ # Handle facetgrids first if row or col: @@ -1252,7 +1256,8 @@ def lines( Line plot of DataArray values. Wraps :func:`matplotlib:matplotlib.collections.LineCollection` which allows - efficient plotting of many lines. + efficient plotting of many lines in a similar fashion to + :py:func:`xarray.plot.scatter`. """ if "u" in kwargs or "v" in kwargs: raise ValueError("u, v are not allowed in lines plots.") diff --git a/xarray/plot/dataset_plot.py b/xarray/plot/dataset_plot.py index 295385efb26..66cc10ae7c2 100644 --- a/xarray/plot/dataset_plot.py +++ b/xarray/plot/dataset_plot.py @@ -1079,7 +1079,8 @@ def lines( Line plot Dataset data variables against each other. Wraps :func:`matplotlib:matplotlib.collections.LineCollection` which allows - efficient plotting of many lines. + efficient plotting of many lines in a similar fashion to + :py:func:`xarray.plot.scatter`. """ locals_ = locals() del locals_["ds"] From e4f52588ee8338c0a28578462cded05b4c817f3d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 12:58:10 +0000 Subject: [PATCH 097/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/tests/test_plot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index c4cdd3387b2..b58eb8dca67 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3562,6 +3562,8 @@ def test_plot1d_lines_facetgrid_legend() -> None: 2.449489742783178, ] np.testing.assert_allclose(expected_size, actual_size) + + def test_9155() -> None: # A test for types from issue #9155 From eda1d74fe72fc0e136bc71f46489c581ab28d6a6 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:05:59 +0200 Subject: [PATCH 098/102] fix bad merge --- xarray/tests/test_plot.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index c4cdd3387b2..b2bdee4f38e 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3562,6 +3562,9 @@ def test_plot1d_lines_facetgrid_legend() -> None: 2.449489742783178, ] np.testing.assert_allclose(expected_size, actual_size) + + +@requires_matplotlib def test_9155() -> None: # A test for types from issue #9155 From 77b2c2c81e104cabd7070907ba6f9bc2d11698de Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 20:04:22 +0000 Subject: [PATCH 099/102] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/plot/facetgrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/facetgrid.py b/xarray/plot/facetgrid.py index 73b1e88d085..9175e46de62 100644 --- a/xarray/plot/facetgrid.py +++ b/xarray/plot/facetgrid.py @@ -495,7 +495,7 @@ def map_plot1d( if self._single_group: full = tuple( {self._single_group: v} - for v in range(0, self.data[self._single_group].size) + for v in range(self.data[self._single_group].size) ) empty = (None,) * (self._nrow * self._ncol - len(full)) name_d = full + empty From e0f7e057c9eda3dd8b09032b47baa98b31a3ce6d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 20 Dec 2024 21:28:04 +0100 Subject: [PATCH 100/102] make mypy happy again --- xarray/tests/test_plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 083a9134a9a..fc3a255868b 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -3519,8 +3519,8 @@ def test_plot1d_lines_color(plotfunc: str, x="z", color="b") -> None: coll = ax.collections[0] # Make sure color is respected: - expected_color = to_rgba_array(color) - actual_color = coll.get_edgecolor() + expected_color = np.asarray(to_rgba_array(color)) + actual_color = np.asarray(coll.get_edgecolor()) np.testing.assert_allclose(expected_color, actual_color) @@ -3543,7 +3543,7 @@ def test_plot1d_lines_linestyle(plotfunc: str, x="z", linestyle="dashed") -> Non coll = ax.collections[0] # Make sure linestyle is respected: - w = coll.get_linewidth().item() + w = np.atleast_1d(coll.get_linewidth())[0] expected_linestyle = [_scale_dashes(*_get_dash_pattern(linestyle), w)] actual_linestyle = coll.get_linestyle() assert expected_linestyle == actual_linestyle From dec570ce5331556ac5546e8629263147d7bf0e4d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 20 Dec 2024 21:31:51 +0100 Subject: [PATCH 101/102] Update whats-new.rst --- doc/whats-new.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 6981307ce0e..d875c27a3e9 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -36,6 +36,10 @@ New Features iso8601-parser (:pull:`9885`). By `Kai Mühlbauer `_. +- Added new plot method `lines` which allows creating line plots efficiently in + a similiar manner to `scatter`. (:pull:`7173`) + By `Jimmy Westling `_. + Breaking changes ~~~~~~~~~~~~~~~~ - Methods including ``dropna``, ``rank``, ``idxmax``, ``idxmin`` require @@ -362,10 +366,6 @@ New Features By `Mathijs Verhaegh `_. - Allow chunking for arrays with duplicated dimension names (:issue:`8759`, :pull:`9099`). By `Martin Raspaud `_. -- Added new plot method `lines` which allows creating line plots efficiently in - a similiar manner to `scatter`. (:pull:`7173`) - By `Jimmy Westling `_. - - Extract the source url from fsspec objects (:issue:`9142`, :pull:`8923`). By `Justus Magin `_. - Add :py:meth:`DataArray.drop_attrs` & :py:meth:`Dataset.drop_attrs` methods, From f06758b792c9764a3266c86d69506f88c42af531 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 20 Dec 2024 21:34:16 +0100 Subject: [PATCH 102/102] Update whats-new.rst --- doc/whats-new.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index d875c27a3e9..da17d50008d 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -36,8 +36,8 @@ New Features iso8601-parser (:pull:`9885`). By `Kai Mühlbauer `_. -- Added new plot method `lines` which allows creating line plots efficiently in - a similiar manner to `scatter`. (:pull:`7173`) +- Added new plot method :py:meth:`DataArray.plot.lines` which allows creating line plots efficiently in + a similiar manner to :py:meth:`DataArray.plot.scatter`, also available for datasets. (:pull:`7173`) By `Jimmy Westling `_. Breaking changes