24
24
25
25
26
26
@dataclass
27
- class Scatter (Mark ):
28
- """
29
- A point mark defined by strokes with optional fills.
30
- """
31
- # TODO retype marker as MappableMarker
32
- marker : MappableString = Mappable (rc = "scatter.marker" , grouping = False )
33
- stroke : MappableFloat = Mappable (.75 , grouping = False ) # TODO rcParam?
34
- pointsize : MappableFloat = Mappable (3 , grouping = False ) # TODO rcParam?
35
- color : MappableColor = Mappable ("C0" , grouping = False )
36
- alpha : MappableFloat = Mappable (1 , grouping = False ) # TODO auto alpha?
37
- fill : MappableBool = Mappable (True , grouping = False )
38
- fillcolor : MappableColor = Mappable (depend = "color" , grouping = False )
39
- fillalpha : MappableFloat = Mappable (.2 , grouping = False )
27
+ class DotBase (Mark ):
40
28
41
29
def _resolve_paths (self , data ):
42
30
@@ -60,28 +48,14 @@ def _resolve_properties(self, data, scales):
60
48
61
49
resolved = resolve_properties (self , data , scales )
62
50
resolved ["path" ] = self ._resolve_paths (resolved )
51
+ resolved ["size" ] = resolved ["pointsize" ] ** 2
63
52
64
- if isinstance (data , dict ): # TODO need a better way to check
53
+ if isinstance (data , dict ): # Properties for single dot
65
54
filled_marker = resolved ["marker" ].is_filled ()
66
55
else :
67
56
filled_marker = [m .is_filled () for m in resolved ["marker" ]]
68
57
69
- resolved ["linewidth" ] = resolved ["stroke" ]
70
58
resolved ["fill" ] = resolved ["fill" ] * filled_marker
71
- resolved ["size" ] = resolved ["pointsize" ] ** 2
72
-
73
- resolved ["edgecolor" ] = resolve_color (self , data , "" , scales )
74
- resolved ["facecolor" ] = resolve_color (self , data , "fill" , scales )
75
-
76
- # Because only Dot, and not Scatter, has an edgestyle
77
- resolved .setdefault ("edgestyle" , (0 , None ))
78
-
79
- fc = resolved ["facecolor" ]
80
- if isinstance (fc , tuple ):
81
- resolved ["facecolor" ] = fc [0 ], fc [1 ], fc [2 ], fc [3 ] * resolved ["fill" ]
82
- else :
83
- fc [:, 3 ] = fc [:, 3 ] * resolved ["fill" ] # TODO Is inplace mod a problem?
84
- resolved ["facecolor" ] = fc
85
59
86
60
return resolved
87
61
@@ -129,33 +103,31 @@ def _legend_artist(
129
103
)
130
104
131
105
132
- # TODO change this to depend on ScatterBase?
133
106
@dataclass
134
- class Dot (Scatter ):
107
+ class Dot (DotBase ):
135
108
"""
136
- A point mark defined by shape with optional edges .
109
+ A mark suitable for dot plots or less-dense scatterplots .
137
110
"""
138
111
marker : MappableString = Mappable ("o" , grouping = False )
112
+ pointsize : MappableFloat = Mappable (6 , grouping = False ) # TODO rcParam?
113
+ stroke : MappableFloat = Mappable (.75 , grouping = False ) # TODO rcParam?
139
114
color : MappableColor = Mappable ("C0" , grouping = False )
140
115
alpha : MappableFloat = Mappable (1 , grouping = False )
141
116
fill : MappableBool = Mappable (True , grouping = False )
142
117
edgecolor : MappableColor = Mappable (depend = "color" , grouping = False )
143
118
edgealpha : MappableFloat = Mappable (depend = "alpha" , grouping = False )
144
- pointsize : MappableFloat = Mappable (6 , grouping = False ) # TODO rcParam?
145
119
edgewidth : MappableFloat = Mappable (.5 , grouping = False ) # TODO rcParam?
146
120
edgestyle : MappableStyle = Mappable ("-" , grouping = False )
147
121
148
122
def _resolve_properties (self , data , scales ):
149
- # TODO this is maybe a little hacky, is there a better abstraction?
150
- resolved = super ()._resolve_properties (data , scales )
151
123
124
+ resolved = super ()._resolve_properties (data , scales )
152
125
filled = resolved ["fill" ]
153
126
154
127
main_stroke = resolved ["stroke" ]
155
128
edge_stroke = resolved ["edgewidth" ]
156
129
resolved ["linewidth" ] = np .where (filled , edge_stroke , main_stroke )
157
130
158
- # Overwrite the colors that the super class set
159
131
main_color = resolve_color (self , data , "" , scales )
160
132
edge_color = resolve_color (self , data , "edge" , scales )
161
133
@@ -166,9 +138,43 @@ def _resolve_properties(self, data, scales):
166
138
167
139
filled = np .squeeze (filled )
168
140
if isinstance (main_color , tuple ):
141
+ # TODO handle this in resolve_color
169
142
main_color = tuple ([* main_color [:3 ], main_color [3 ] * filled ])
170
143
else :
171
144
main_color = np .c_ [main_color [:, :3 ], main_color [:, 3 ] * filled ]
172
145
resolved ["facecolor" ] = main_color
173
146
174
147
return resolved
148
+
149
+
150
+ @dataclass
151
+ class Dots (DotBase ):
152
+ """
153
+ A dot mark defined by strokes to better handle overplotting.
154
+ """
155
+ # TODO retype marker as MappableMarker
156
+ marker : MappableString = Mappable (rc = "scatter.marker" , grouping = False )
157
+ pointsize : MappableFloat = Mappable (3 , grouping = False ) # TODO rcParam?
158
+ stroke : MappableFloat = Mappable (.75 , grouping = False ) # TODO rcParam?
159
+ color : MappableColor = Mappable ("C0" , grouping = False )
160
+ alpha : MappableFloat = Mappable (1 , grouping = False ) # TODO auto alpha?
161
+ fill : MappableBool = Mappable (True , grouping = False )
162
+ fillcolor : MappableColor = Mappable (depend = "color" , grouping = False )
163
+ fillalpha : MappableFloat = Mappable (.2 , grouping = False )
164
+
165
+ def _resolve_properties (self , data , scales ):
166
+
167
+ resolved = super ()._resolve_properties (data , scales )
168
+ resolved ["linewidth" ] = resolved .pop ("stroke" )
169
+ resolved ["facecolor" ] = resolve_color (self , data , "fill" , scales )
170
+ resolved ["edgecolor" ] = resolve_color (self , data , "" , scales )
171
+ resolved .setdefault ("edgestyle" , (0 , None ))
172
+
173
+ fc = resolved ["facecolor" ]
174
+ if isinstance (fc , tuple ):
175
+ resolved ["facecolor" ] = fc [0 ], fc [1 ], fc [2 ], fc [3 ] * resolved ["fill" ]
176
+ else :
177
+ fc [:, 3 ] = fc [:, 3 ] * resolved ["fill" ] # TODO Is inplace mod a problem?
178
+ resolved ["facecolor" ] = fc
179
+
180
+ return resolved
0 commit comments