Skip to content

Commit a767d66

Browse files
authored
Tweak nominal scale axes akin to categorical axes in classic seaborn (#3069)
1 parent 85c8ed6 commit a767d66

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed

doc/whatsnew/v0.12.1.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ v0.12.1 (Unreleased)
66

77
- |Feature| Added the :class:`objects.Perc` stat (:pr:`3063`).
88

9-
- |Feature| The :class:`Band` and :class:`Range` marks will now cover the full extent of the data if `min` / `max` variables are not explicitly assigned or added in a transform (:pr:`3056`).
9+
- |Feature| The :class:`objects.Band` and :class:`objects.Range` marks will now cover the full extent of the data if `min` / `max` variables are not explicitly assigned or added in a transform (:pr:`3056`).
1010

11-
- |Enhancement| The :class:`Jitter` move now applies a small amount of jitter by default (:pr:`3066`).
11+
- |Enhancement| |Defaults| The :class:`objects.Jitter` move now applies a small amount of jitter by default (:pr:`3066`).
1212

13-
- |Enhancement| Marks that sort along the orient axis (e.g. :class:`Line`) now use a stable algorithm (:pr:`3064`).
13+
- |Enhancement| |Defaults| Axes with a :class:`objects.Nominal` scale now appear like categorical axes in class seaborn, with fixed margins, no grid, and an inverted y axis (:pr:`3069`).
14+
15+
- |Enhancement| Marks that sort along the orient axis (e.g. :class:`objects.Line`) now use a stable algorithm (:pr:`3064`).
1416

1517
- |Enhancement| |Fix| Add a `label` parameter to :func:`pointplot`, which addresses a regression in 0.12.0 when :func:`pointplot` is passed to :class:`FacetGrid` (:pr:`3016`).
1618

seaborn/_core/plot.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from seaborn._stats.base import Stat
2626
from seaborn._core.data import PlotData
2727
from seaborn._core.moves import Move
28-
from seaborn._core.scales import Scale
28+
from seaborn._core.scales import Scale, Nominal
2929
from seaborn._core.subplots import Subplots
3030
from seaborn._core.groupby import GroupBy
3131
from seaborn._core.properties import PROPERTIES, Property
@@ -1238,7 +1238,6 @@ def _setup_scales(
12381238
# This only affects us when sharing *paired* axes. This is a novel/niche
12391239
# behavior, so we will raise rather than hack together a workaround.
12401240
if axis is not None and Version(mpl.__version__) < Version("3.4.0"):
1241-
from seaborn._core.scales import Nominal
12421241
paired_axis = axis in p._pair_spec.get("structure", {})
12431242
cat_scale = isinstance(scale, Nominal)
12441243
ok_dim = {"x": "col", "y": "row"}[axis]
@@ -1631,6 +1630,7 @@ def _finalize_figure(self, p: Plot) -> None:
16311630
ax = sub["ax"]
16321631
for axis in "xy":
16331632
axis_key = sub[axis]
1633+
axis_obj = getattr(ax, f"{axis}axis")
16341634

16351635
# Axis limits
16361636
if axis_key in p._limits:
@@ -1644,6 +1644,17 @@ def _finalize_figure(self, p: Plot) -> None:
16441644
hi = cast(float, hi) + 0.5
16451645
ax.set(**{f"{axis}lim": (lo, hi)})
16461646

1647+
# Nominal scale special-casing
1648+
if isinstance(self._scales.get(axis_key), Nominal):
1649+
axis_obj.grid(False, which="both")
1650+
if axis_key not in p._limits:
1651+
nticks = len(axis_obj.get_major_ticks())
1652+
lo, hi = -.5, nticks - .5
1653+
if axis == "y":
1654+
lo, hi = hi, lo
1655+
set_lim = getattr(ax, f"set_{axis}lim")
1656+
set_lim(lo, hi, auto=None)
1657+
16471658
engine_default = None if p._target is not None else "tight"
16481659
layout_engine = p._layout_spec.get("engine", engine_default)
16491660
set_layout_engine(self._figure, layout_engine)

tests/_core/test_plot.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,28 @@ def test_undefined_variable_raises(self):
645645
with pytest.raises(RuntimeError, match=err):
646646
p.plot()
647647

648+
def test_nominal_x_axis_tweaks(self):
649+
650+
p = Plot(x=["a", "b", "c"], y=[1, 2, 3])
651+
ax1 = p.plot()._figure.axes[0]
652+
assert ax1.get_xlim() == (-.5, 2.5)
653+
assert not any(x.get_visible() for x in ax1.xaxis.get_gridlines())
654+
655+
lim = (-1, 2.1)
656+
ax2 = p.limit(x=lim).plot()._figure.axes[0]
657+
assert ax2.get_xlim() == lim
658+
659+
def test_nominal_y_axis_tweaks(self):
660+
661+
p = Plot(x=[1, 2, 3], y=["a", "b", "c"])
662+
ax1 = p.plot()._figure.axes[0]
663+
assert ax1.get_ylim() == (2.5, -.5)
664+
assert not any(y.get_visible() for y in ax1.yaxis.get_gridlines())
665+
666+
lim = (-1, 2.1)
667+
ax2 = p.limit(y=lim).plot()._figure.axes[0]
668+
assert ax2.get_ylim() == lim
669+
648670

649671
class TestPlotting:
650672

0 commit comments

Comments
 (0)