Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 82dee99

Browse files
committed
add markers hatch
1 parent 36e67f7 commit 82dee99

File tree

1 file changed

+88
-19
lines changed

1 file changed

+88
-19
lines changed

lib/matplotlib/hatch.py

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,12 @@ def get_path(hatchpattern, density=6):
228228
attrs = [
229229
# ("color", "black"), For now it is an attr of gc
230230
# ("alpha", 1.0),
231-
('scale', 6.0),
231+
('scale', 6),
232232
('weight', 1.0),
233233
('angle', 0.0),
234234
('random_rotation', False),
235235
('staggered', False),
236-
('random_placement', False),
236+
('filled', True),
237237
]
238238

239239

@@ -242,16 +242,19 @@ def __init__(self, hatchpattern, **kwargs):
242242
self.hatchpattern = hatchpattern
243243
self.kwargs = {attr: kwargs.get(attr, default) for attr, default in attrs}
244244

245-
def rotate_path(self, vertices, angle=None):
245+
def rotate_path(self, vertices, angle=None, scale_correction=True):
246+
vertices = vertices.copy()
247+
246248
if angle is None:
247249
angle = self.kwargs["angle"]
248250
angle_rad = np.deg2rad(angle)
249251

250252
center = np.mean(vertices, axis=0)
251253
vertices -= center
252254

253-
scaling = np.sin(angle_rad) + np.cos(angle_rad)
254-
vertices *= scaling
255+
if scale_correction:
256+
scaling = abs(np.sin(angle_rad)) + abs(np.cos(angle_rad))
257+
vertices *= scaling
255258

256259
rotation_matrix = np.array(
257260
[
@@ -267,19 +270,85 @@ def get_vertices_and_codes(self, hatch_buffer_size=100):
267270
self.hatch_buffer_size = hatch_buffer_size
268271
vertices, codes = np.empty((0, 2)), np.empty(0, Path.code_type)
269272

270-
for hatchpattern in self.hatchpattern:
271-
func = hatchpatterns[hatchpattern]
272-
for f in func:
273-
verts, cods = f(self)
274-
vertices = np.concatenate((vertices, verts))
275-
codes = np.concatenate((codes, cods))
273+
if self.hatchpattern in hatchpatterns:
274+
# This is for line hatches
275+
for func in np.atleast_1d(hatchpatterns[self.hatchpattern]):
276+
vertices_part, codes_part = func(self)
277+
vertices_part = self.rotate_path(vertices_part)
278+
279+
vertices = np.concatenate((vertices, vertices_part))
280+
codes = np.concatenate((codes, codes_part))
281+
else:
282+
# This is for marker hatches
283+
if self.hatchpattern not in MarkerHatchStyle.marker_paths:
284+
raise ValueError(f"Unknown hatch pattern: {self.hatchpattern}")
285+
func = MarkerHatchStyle.marker_pattern
286+
vertices_part, codes_part = func(self)
287+
288+
vertices = np.concatenate((vertices, vertices_part))
289+
codes = np.concatenate((codes, codes_part))
276290

277-
vertices = self.rotate_path(vertices)
278291
return vertices, codes
279292

280293

281294
class MarkerHatchStyle(HatchStyle):
282-
pass
295+
marker_paths = {
296+
'o': Path.unit_circle,
297+
'O': Path.unit_circle,
298+
'*': (Path.unit_regular_star, 5), # TODO: is there a better way to do this?
299+
}
300+
301+
# TODO: saner defaults or no?
302+
marker_sizes = {
303+
'o': 0.2,
304+
'O': 0.35,
305+
'*': 1.0 / 3.0,
306+
}
307+
308+
def _get_marker_path(marker):
309+
func = np.atleast_1d(MarkerHatchStyle.marker_paths[marker])
310+
path = func[0](*func[1:])
311+
size = MarkerHatchStyle.marker_sizes[marker]
312+
313+
return Path(
314+
vertices=path.vertices * size,
315+
codes=path.codes,
316+
)
317+
318+
def marker_pattern(hatchstyle):
319+
size = hatchstyle.kwargs['weight']
320+
num_rows = round(
321+
hatchstyle.kwargs['scale'] * hatchstyle.hatch_buffer_size / 100.0
322+
)
323+
path = MarkerHatchStyle._get_marker_path(hatchstyle.hatchpattern)
324+
shape_vertices = hatchstyle.rotate_path(path.vertices, scale_correction=False)
325+
shape_codes = path.codes
326+
327+
offset = 1.0 / num_rows
328+
shape_vertices = shape_vertices * offset * size
329+
330+
if not hatchstyle.kwargs['filled']:
331+
shape_vertices = np.concatenate(
332+
[shape_vertices, shape_vertices[::-1] * 0.9]
333+
)
334+
shape_codes = np.concatenate([shape_codes, shape_codes])
335+
336+
vertices_parts = []
337+
codes_parts = []
338+
for row in range(num_rows + 1):
339+
if row % 2 == 0:
340+
cols = np.linspace(0, 1, num_rows + 1)
341+
else:
342+
cols = np.linspace(offset / 2, 1 - offset / 2, num_rows)
343+
row_pos = row * offset
344+
for col_pos in cols:
345+
vertices_parts.append(shape_vertices + [col_pos, row_pos])
346+
codes_parts.append(shape_codes)
347+
348+
vertices = np.concatenate(vertices_parts)
349+
codes = np.concatenate(codes_parts)
350+
351+
return vertices, codes
283352

284353

285354
class LineHatchStyle(HatchStyle):
@@ -371,10 +440,10 @@ def south_east(hatchstyle):
371440

372441

373442
hatchpatterns = {
374-
"-": (LineHatchStyle.horizontal,),
375-
"|": (LineHatchStyle.vertical,),
376-
"/": (LineHatchStyle.north_east,),
377-
"\\": (LineHatchStyle.south_east,),
378-
"+": (LineHatchStyle.horizontal, LineHatchStyle.vertical),
379-
"x": (LineHatchStyle.north_east, LineHatchStyle.south_east),
443+
'-': LineHatchStyle.horizontal,
444+
'|': LineHatchStyle.vertical,
445+
'/': LineHatchStyle.north_east,
446+
'\\': LineHatchStyle.south_east,
447+
'+': (LineHatchStyle.horizontal, LineHatchStyle.vertical),
448+
'x': (LineHatchStyle.north_east, LineHatchStyle.south_east),
380449
}

0 commit comments

Comments
 (0)