diff --git a/seaborn/_core/plot.py b/seaborn/_core/plot.py index 73e957623e..c8615f9b9a 100644 --- a/seaborn/_core/plot.py +++ b/seaborn/_core/plot.py @@ -428,7 +428,7 @@ def plot(self, pyplot=False) -> Plot: # TODO this should be configurable if not self._figure.get_constrained_layout(): - self._figure.tight_layout() + self._figure.set_tight_layout(True) # TODO many methods will (confusingly) have no effect if invoked after # Plot.plot is (manually) called. We should have some way of raising from @@ -529,7 +529,22 @@ def _setup_mappings(self) -> None: def _setup_orderings(self) -> None: - ... + orderings = {} + + variables = set(self._data.frame) + for layer in self._layers: + variables |= set(layer.data.frame) + + for var in variables: + # TODO should the order be a property of the Semantic or the Mapping? + if var in self._mappings and self._mappings[var].levels is not None: + # orderings[var] = self._mappings[var].order + # TODO FIXME:mappings mapping should always have order (can be None) + orderings[var] = self._mappings[var].levels + elif self._scales[var].order is not None: + orderings[var] = self._scales[var].order + + self._orderings = orderings def _setup_figure(self, pyplot: bool = False) -> None: @@ -563,21 +578,22 @@ def _setup_figure(self, pyplot: bool = False) -> None: ax = sub["ax"] for axis in "xy": axis_key = sub[axis] - scale = self._scales[axis_key]._scale - if LooseVersion(mpl.__version__) < "3.4": - # The ability to pass a BaseScale instance to Axes.set_{axis}scale - # was added to matplotlib in version 3.4.0: - # https://github.com/matplotlib/matplotlib/pull/19089 - # Workaround: use the scale name, which is restrictive only - # if the user wants to define a custom scale. - # Additionally, setting the scale after updating the units breaks - # in some cases on older versions of matplotlib (with older pandas?) - # so only do it if necessary. - axis_obj = getattr(ax, f"{axis}axis") - if axis_obj.get_scale() != scale.name: - ax.set(**{f"{axis}scale": scale.name}) - else: - ax.set(**{f"{axis}scale": scale}) + if axis_key in self._scales: + scale = self._scales[axis_key]._scale + if LooseVersion(mpl.__version__) < "3.4": + # The ability to pass a BaseScale instance to + # Axes.set_{axis}scale was added to matplotlib in version 3.4.0: + # https://github.com/matplotlib/matplotlib/pull/19089 + # Workaround: use the scale name, which is restrictive only + # if the user wants to define a custom scale. + # Additionally, setting the scale after updating units breaks in + # some cases on older versions of matplotlib (/ older pandas?) + # so only do it if necessary. + axis_obj = getattr(ax, f"{axis}axis") + if axis_obj.get_scale() != scale.name: + ax.set(**{f"{axis}scale": scale.name}) + else: + ax.set(**{f"{axis}scale": scale}) # --- Figure annotation for sub in subplots: diff --git a/seaborn/tests/_core/test_plot.py b/seaborn/tests/_core/test_plot.py index 85547a94ef..5a98a72d9e 100644 --- a/seaborn/tests/_core/test_plot.py +++ b/seaborn/tests/_core/test_plot.py @@ -114,27 +114,18 @@ def test_vector_variables_no_index(self, long_df): assert p._data._source_data is None assert p._data._source_vars.keys() == variables.keys() - def test_scales(self, long_df): - - p = Plot(long_df, x="x", y="y") - for var in "xy": - assert var in p._scales - assert p._scales[var].type == "unknown" - class TestLayerAddition: def test_without_data(self, long_df): - p = Plot(long_df, x="x", y="y").add(MockMark()) - p._setup_layers() + p = Plot(long_df, x="x", y="y").add(MockMark()).plot() layer, = p._layers assert_frame_equal(p._data.frame, layer.data.frame) def test_with_new_variable_by_name(self, long_df): - p = Plot(long_df, x="x").add(MockMark(), y="y") - p._setup_layers() + p = Plot(long_df, x="x").add(MockMark(), y="y").plot() layer, = p._layers assert layer.data.frame.columns.to_list() == ["x", "y"] for var in "xy": @@ -143,8 +134,7 @@ def test_with_new_variable_by_name(self, long_df): def test_with_new_variable_by_vector(self, long_df): - p = Plot(long_df, x="x").add(MockMark(), y=long_df["y"]) - p._setup_layers() + p = Plot(long_df, x="x").add(MockMark(), y=long_df["y"]).plot() layer, = p._layers assert layer.data.frame.columns.to_list() == ["x", "y"] for var in "xy": @@ -153,8 +143,7 @@ def test_with_new_variable_by_vector(self, long_df): def test_with_late_data_definition(self, long_df): - p = Plot().add(MockMark(), data=long_df, x="x", y="y") - p._setup_layers() + p = Plot().add(MockMark(), data=long_df, x="x", y="y").plot() layer, = p._layers assert layer.data.frame.columns.to_list() == ["x", "y"] for var in "xy": @@ -165,8 +154,7 @@ def test_with_new_data_definition(self, long_df): long_df_sub = long_df.sample(frac=.5) - p = Plot(long_df, x="x", y="y").add(MockMark(), data=long_df_sub) - p._setup_layers() + p = Plot(long_df, x="x", y="y").add(MockMark(), data=long_df_sub).plot() layer, = p._layers assert layer.data.frame.columns.to_list() == ["x", "y"] for var in "xy": @@ -177,8 +165,7 @@ def test_with_new_data_definition(self, long_df): def test_drop_variable(self, long_df): - p = Plot(long_df, x="x", y="y").add(MockMark(), y=None) - p._setup_layers() + p = Plot(long_df, x="x", y="y").add(MockMark(), y=None).plot() layer, = p._layers assert layer.data.frame.columns.to_list() == ["x"] assert "y" not in layer @@ -237,25 +224,18 @@ class TestAxisScaling: def test_inference(self, long_df): for col, scale_type in zip("zat", ["numeric", "categorical", "datetime"]): - p = Plot(long_df, x=col, y=col).add(MockMark()) - for var in "xy": - assert p._scales[var].type == "unknown" - p._setup_layers() - p._setup_scales() + p = Plot(long_df, x=col, y=col).add(MockMark()).plot() for var in "xy": assert p._scales[var].type == scale_type def test_inference_concatenates(self): - p = Plot(x=[1, 2, 3]).add(MockMark(), x=["a", "b", "c"]) - p._setup_layers() - p._setup_scales() + p = Plot(x=[1, 2, 3]).add(MockMark(), x=["a", "b", "c"]).plot() assert p._scales["x"].type == "categorical" def test_categorical_explicit_order(self): p = Plot(x=["b", "c", "a"]).scale_categorical("x", order=["c", "a", "b"]) - scl = p._scales["x"] assert scl.type == "categorical" assert scl.cast(pd.Series(["c", "a", "b"])).cat.codes.to_list() == [0, 1, 2] @@ -263,7 +243,6 @@ def test_categorical_explicit_order(self): def test_numeric_as_categorical(self): p = Plot(x=[2, 1, 3]).scale_categorical("x") - scl = p._scales["x"] assert scl.type == "categorical" assert scl.cast(pd.Series([1, 2, 3])).cat.codes.to_list() == [0, 1, 2] @@ -271,7 +250,6 @@ def test_numeric_as_categorical(self): def test_numeric_as_categorical_explicit_order(self): p = Plot(x=[1, 2, 3]).scale_categorical("x", order=[2, 1, 3]) - scl = p._scales["x"] assert scl.type == "categorical" assert scl.cast(pd.Series([2, 1, 3])).cat.codes.to_list() == [0, 1, 2]