Skip to content

Commit 87e0972

Browse files
authored
Improve robustness to empty data in Plot and Nominal (#3202)
* Improve robustness to missing data in Plot and Nominal * Fix Plot.on tests to work with new logic
1 parent d25872b commit 87e0972

File tree

5 files changed

+17
-9
lines changed

5 files changed

+17
-9
lines changed

doc/whatsnew/v0.12.2.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ v0.12.2 (Unreleased)
88

99
- |Fix| Fixed a bug where legends for numeric variables with large values with be incorrectly shown (i.e. with a missing offset or exponent; :pr:`3187`).
1010

11+
- |Fix| Improve robustness to empty data in several components of the objects interface (:pr:`3202`).
12+
1113
- |Fix| Fixed a regression in v0.12.0 where manually-added labels could have duplicate legend entries (:pr:`3116`).
1214

1315
- |Fix| Fixed a bug in :func:`histplot` with `kde=True` and `log_scale=True` where the curve was not scaled properly (:pr:`3173`).

seaborn/_core/plot.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,6 @@ def _setup_split_generator(
14661466
self, grouping_vars: list[str], df: DataFrame, subplots: list[dict[str, Any]],
14671467
) -> Callable[[], Generator]:
14681468

1469-
allow_empty = False # TODO will need to recreate previous categorical plots
1470-
14711469
grouping_keys = []
14721470
grouping_vars = [
14731471
v for v in grouping_vars if v in df and v not in ["col", "row"]
@@ -1506,7 +1504,8 @@ def split_generator(keep_na=False) -> Generator:
15061504
subplot_keys[dim] = view[dim]
15071505

15081506
if not grouping_vars or not any(grouping_keys):
1509-
yield subplot_keys, axes_df.copy(), view["ax"]
1507+
if not axes_df.empty:
1508+
yield subplot_keys, axes_df.copy(), view["ax"]
15101509
continue
15111510

15121511
grouped_df = axes_df.groupby(grouping_vars, sort=False, as_index=False)
@@ -1526,7 +1525,7 @@ def split_generator(keep_na=False) -> Generator:
15261525
# case this option could be removed
15271526
df_subset = axes_df.loc[[]]
15281527

1529-
if df_subset.empty and not allow_empty:
1528+
if df_subset.empty:
15301529
continue
15311530

15321531
sub_vars = dict(zip(grouping_vars, key))

seaborn/_core/scales.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def _setup(
163163
new = new.label()
164164

165165
# TODO flexibility over format() which isn't great for numbers / dates
166-
stringify = np.vectorize(format)
166+
stringify = np.vectorize(format, otypes=["object"])
167167

168168
units_seed = categorical_order(data, new.order)
169169

tests/_core/test_plot.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -680,8 +680,9 @@ def test_matplotlib_object_creation(self):
680680
def test_empty(self):
681681

682682
m = MockMark()
683-
Plot().plot()
683+
Plot().add(m).plot()
684684
assert m.n_splits == 0
685+
assert not m.passed_data
685686

686687
def test_no_orient_variance(self):
687688

@@ -1086,7 +1087,7 @@ def test_on_axes(self):
10861087

10871088
ax = mpl.figure.Figure().subplots()
10881089
m = MockMark()
1089-
p = Plot().on(ax).add(m).plot()
1090+
p = Plot([1], [2]).on(ax).add(m).plot()
10901091
assert m.passed_axes == [ax]
10911092
assert p._figure is ax.figure
10921093

@@ -1095,7 +1096,7 @@ def test_on_figure(self, facet):
10951096

10961097
f = mpl.figure.Figure()
10971098
m = MockMark()
1098-
p = Plot().on(f).add(m)
1099+
p = Plot([1, 2], [3, 4]).on(f).add(m)
10991100
if facet:
11001101
p = p.facet(["a", "b"])
11011102
p = p.plot()
@@ -1112,7 +1113,7 @@ def test_on_subfigure(self, facet):
11121113
sf1, sf2 = mpl.figure.Figure().subfigures(2)
11131114
sf1.subplots()
11141115
m = MockMark()
1115-
p = Plot().on(sf2).add(m)
1116+
p = Plot([1, 2], [3, 4]).on(sf2).add(m)
11161117
if facet:
11171118
p = p.facet(["a", "b"])
11181119
p = p.plot()

tests/_core/test_scales.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,12 @@ class MockProperty(IntervalProperty):
555555
s = Nominal((2, 4))._setup(x, MockProperty())
556556
assert_array_equal(s(x), [4, np.sqrt(10), 2, np.sqrt(10)])
557557

558+
def test_empty_data(self):
559+
560+
x = pd.Series([], dtype=object, name="x")
561+
s = Nominal()._setup(x, Coordinate())
562+
assert_array_equal(s(x), [])
563+
558564

559565
class TestTemporal:
560566

0 commit comments

Comments
 (0)