Skip to content

Commit

Permalink
Make it optional to have x/y scale defined
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Waskom committed Sep 26, 2021
1 parent 7e758f8 commit b706c89
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 47 deletions.
50 changes: 33 additions & 17 deletions seaborn/_core/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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:
Expand Down
38 changes: 8 additions & 30 deletions seaborn/tests/_core/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand All @@ -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":
Expand All @@ -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":
Expand All @@ -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":
Expand All @@ -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
Expand Down Expand Up @@ -237,41 +224,32 @@ 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]

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]

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]
Expand Down

0 comments on commit b706c89

Please sign in to comment.