10000 Fix geom_point to use color for unfilled shapes · has2k1/plotnine@d44690c · GitHub
[go: up one dir, main page]

Skip to content

Commit d44690c

Browse files
committed
Fix geom_point to use color for unfilled shapes
To maintain back-compatibility, matplotlib decided to ignore the issue. fixes #100 Ref: matplotlib/matplotlib#10008, matplotlib/matplotlib#17850
1 parent 37b0abb commit d44690c

File tree

6 files changed

+68
-12
lines changed

6 files changed

+68
-12
lines changed

doc/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ Bug Fixes
5555
:class:`~plotnine.scales.scale_x_discrete` to work properly with ``None``
5656
values. :issue:`523`
5757

58+
- Fixed :class:`~plotnine.geoms.geom_point` to respect not to use the ``fill``
59+
mapping on unfilled shapes. :issue:`100`
60+
5861
Enhancements
5962
************
6063

plotnine/geoms/geom_point.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from ..utils import to_rgba, SIZE_FACTOR
55
from ..doctools import document
6+
from ..scales.scale_shape import FILLED_SHAPES, UNFILLED_SHAPES
67
from .geom import geom
78

89

@@ -49,14 +50,23 @@ def draw_unit(data, panel_params, coord, ax, **params):
4950
size = ((data['size']+data['stroke'])**2)*np.pi
5051
stroke = data['stroke'] * SIZE_FACTOR
5152
color = to_rgba(data['color'], data['alpha'])
53+
shape = data.loc[0, 'shape']
5254

5355
# It is common to forget that scatter points are
5456
# filled and slip-up by manually assigning to the
5557
# color instead of the fill. We forgive.
56-
if all(c is None for c in data['fill']):
58+
if shape in FILLED_SHAPES:
59+
if all(c is None for c in data['fill']):
60+
fill = color
61+
else:
62+
fill = to_rgba(data['fill'], data['alpha'])
63+
elif shape in UNFILLED_SHAPES:
5764
fill = color
65+
color = None
5866
else:
59-
fill = to_rgba(data['fill'], data['alpha'])
67+
raise ValueError(
68+
f"geom_point got an unknown shape: {shape}"
69+
)
6070

6171
ax.scatter(
6272
x=data['x'],
@@ -65,7 +75,7 @@ def draw_unit(data, panel_params, coord, ax, **params):
6575
facecolor=fill,
6676
edgecolor=color,
6777
linewidth=stroke,
68-
marker=data.loc[0, 'shape'],
78+
marker=shape,
6979
zorder=params['zorder'],
7080
rasterized=params['raster']
7181
)
@@ -90,13 +100,16 @@ def draw_legend(data, da, lyr):
90100

91101
size = (data['size']+data['stroke'])*SIZE_FACTOR
92102
stroke = data['stroke'] * SIZE_FACTOR
93-
key = mlines.Line2D([0.5*da.width],
94-
[0.5*da.height],
95-
alpha=data['alpha'],
96-
marker=data['shape'],
97-
markersize=size,
98-
markerfacecolor=data['fill'],
99-
markeredgecolor=data['color'],
100-
markeredgewidth=stroke)
103+
104+
key = mlines.Line2D(
105+
[0.5*da.width],
106+
[0.5*da.height],
107+
alpha=data['alpha'],
108+
marker=data['shape'],
109+
markersize=size,
110+
markerfacecolor=data['fill'],
111+
markeredgecolor=data['color'],
112+
markeredgewidth=stroke
113+
)
101114
da.add_artist(key)
102115
return da

plotnine/scales/scale_shape.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
7, # caretdown
4646
)
4747

48+
# For quick lookup
49+
FILLED_SHAPES = set(shapes)
50+
UNFILLED_SHAPES = set(unfilled_shapes)
51+
4852

4953
@document
5054
class scale_shape(scale_discrete):
Loading
Loading

plotnine/tests/test_geom_point.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pandas as pd
22

3-
from plotnine import ggplot, aes, geom_point, theme
3+
from plotnine import ggplot, aes, geom_point, theme, guides
44

55

66
def test_aesthetics():
@@ -49,3 +49,39 @@ def test_no_fill():
4949
color='yellow', fill='gray', size=5, stroke=1.5))
5050

5151
assert p == 'no_fill'
52+
53+
54+
class TestColorFillonUnfilledShape:
55+
df = pd.DataFrame({
56+
'x': range(6),
57+
'y': range(6),
58+
'z': list('aabbcc')
59+
})
60+
p = (ggplot(df, aes('x', 'y'))
61+
+ geom_point(shape='3', size=10, stroke=3)
62+
+ guides(fill=False)
63+
+ theme(subplots_adjust={'right': 0.85})
64+
)
65+
66+
# Color Fill Result
67+
# No No Black
68+
# No Yes Black
69+
# Yes No Color
70+
# Yes Yes Color
71+
72+
def test_no_mapping(self):
73+
assert self.p == 'no_mapping'
74+
75+
def test_fill_only_mapping(self):
76+
p = self.p + aes(fill='x')
77+
# Same as above
78+
assert p == 'no_mapping'
79+
80+
def test_color_only_mapping(self):
81+
p = self.p + aes(color='z')
82+
assert p == 'color_only_mapping'
83+
84+
def test_color_fill_mapping(self):
85+
p = self.p + aes(color='z', fill='x')
86+
# Same as above
87+
assert p == 'color_only_mapping'

0 commit comments

Comments
 (0)
0