88they are meant to be fast for common use cases (e.g., a large set of solid
99line segments).
1010"""
11-
11+ import contextlib
1212import itertools
1313import functools
1414import math
@@ -363,6 +363,32 @@ def _prepare_points(self):
363363
364364 return transform , offset_trf , offsets , paths
365365
366+ @contextlib .contextmanager
367+ def _prep_for_contiguous_drawing (self , renderer , gc ):
368+ # Context manager to wrap the specific rendering commands within draw()
369+
370+ # If supported by the renderer, draw contiguous patches (must be antialiased
371+ # and not stroked) using the "plus" blend mode in an isolated blend group so
372+ # that the fractional alphas at edges are added to make the proper total alpha.
373+ # If the alphas were instead blended as if they were unrelated opacities,
374+ # the resulting alpha would be smaller (i.e., more transparent), which would
375+ # manifest as slightly transparent line artifacts along shared patch edges.
376+ isolate = (renderer ._supports_isolated_group_and_plus_blend_mode
377+ and self ._treat_patches_as_contiguous
378+ and np .all (self ._antialiaseds )
379+ and (self ._edgecolors .size == 0
380+ or np .all (self ._edgecolors [:, 3 ] == 0 )))
381+ if isolate :
382+ blend_mode = gc .get_blend_mode ()
383+ gc .set_blend_mode ("plus" )
384+ renderer .open_blend_group (blend_mode )
385+ try :
386+ yield
387+ finally :
388+ if isolate :
389+ renderer .close_blend_group ()
390+ gc .set_blend_mode (blend_mode )
391+
366392 @artist .allow_rasterization
367393 def draw (self , renderer ):
368394 if not self .get_visible ():
@@ -379,21 +405,6 @@ def draw(self, renderer):
379405
380406 transform , offset_trf , offsets , paths = self ._prepare_points ()
381407
382- # If supported by the renderer, draw contiguous, antialiased patches without
383- # strokes using the "plus" blend mode in an isolated blend group so that the
384- # fractional alphas at edges are added to make the intended total alpha.
385- # If the alphas were instead blended as if they were unrelated opacities,
386- # the resulting alpha would be smaller (i.e., more transparent), which would
387- # manifest as slightly transparent line artifacts along patch edges.
388- isolate = (renderer ._supports_isolated_group_and_plus_blend_mode
389- and self ._treat_patches_as_contiguous
390- and np .all (self ._antialiaseds )
391- and (self ._edgecolors .size == 0 or self ._edgecolors [0 ][3 ] == 0 ))
392- if isolate :
393- blend_mode = self .get_blend_mode ()
394- self .set_blend_mode ("plus" )
395- renderer .open_blend_group (blend_mode )
396-
397408 gc = renderer .new_gc ()
398409 self ._set_gc_clip (gc )
399410 gc .set_blend_mode (self .get_blend_mode ())
@@ -447,9 +458,10 @@ def draw(self, renderer):
447458 gc .set_dashes (* self ._linestyles [0 ])
448459 gc .set_antialiased (self ._antialiaseds [0 ])
449460 gc .set_url (self ._urls [0 ])
450- renderer .draw_markers (
451- gc , paths [0 ], combined_transform .frozen (),
452- mpath .Path (offsets ), offset_trf , tuple (facecolors [0 ]))
461+ with self ._prep_for_contiguous_drawing (renderer , gc ):
462+ renderer .draw_markers (
463+ gc , paths [0 ], combined_transform .frozen (),
464+ mpath .Path (offsets ), offset_trf , tuple (facecolors [0 ]))
453465 else :
454466 # The current new API of draw_path_collection() is provisional
455467 # and will be changed in a future PR.
@@ -512,29 +524,28 @@ def draw(self, renderer):
512524 self ._linewidths , self ._linestyles , self ._antialiaseds , self ._urls ,
513525 "screen" ]
514526
515- if hatchcolors_arg_supported :
516- renderer .draw_path_collection (gc , transform .frozen (), paths ,
517- self .get_transforms (), * args ,
518- hatchcolors = self .get_hatchcolor ())
519- else :
520- if hatchcolors_not_needed :
527+ with self ._prep_for_contiguous_drawing (renderer , gc ):
528+ if hatchcolors_arg_supported :
521529 renderer .draw_path_collection (gc , transform .frozen (), paths ,
522- self .get_transforms (), * args )
530+ self .get_transforms (), * args ,
531+ hatchcolors = self .get_hatchcolor ())
523532 else :
524- path_ids = renderer ._iter_collection_raw_paths (
525- transform .frozen (), paths , self .get_transforms ())
526- for xo , yo , path_id , gc0 , rgbFace in renderer ._iter_collection (
527- gc , list (path_ids ), * args , hatchcolors = self .get_hatchcolor (),
528- ):
529- path , transform = path_id
530- if xo != 0 or yo != 0 :
531- transform = transform .frozen ()
532- transform .translate (xo , yo )
533- renderer .draw_path (gc0 , path , transform , rgbFace )
533+ if hatchcolors_not_needed :
534+ renderer .draw_path_collection (gc , transform .frozen (), paths ,
535+ self .get_transforms (), * args )
536+ else :
537+ path_ids = renderer ._iter_collection_raw_paths (
538+ transform .frozen (), paths , self .get_transforms ())
539+ for xo , yo , path_id , gc0 , rgbFace in renderer ._iter_collection (
540+ gc , list (path_ids ), * args ,
541+ hatchcolors = self .get_hatchcolor (),
542+ ):
543+ path , transform = path_id
544+ if xo != 0 or yo != 0 :
545+ transform = transform .frozen ()
546+ transform .translate (xo , yo )
547+ renderer .draw_path (gc0 , path , transform , rgbFace )
534548
535- if isolate :
536- renderer .close_blend_group ()
537- self .set_blend_mode (blend_mode )
538549 gc .restore ()
539550 renderer .close_group (self .__class__ .__name__ )
540551 self .stale = False
@@ -2548,11 +2559,13 @@ def __init__(self, coordinates, *, antialiased=True, shading='flat',
25482559 super ().__init__ (coordinates = coordinates , shading = shading )
25492560 Collection .__init__ (self , ** kwargs )
25502561
2551- self ._antialiased = antialiased
2562+ self ._antialiaseds = antialiased
25522563 self ._bbox = transforms .Bbox .unit ()
25532564 self ._bbox .update_from_data_xy (self ._coordinates .reshape (- 1 , 2 ))
25542565 self .set_mouseover (False )
25552566
2567+ self ._treat_patches_as_contiguous = True
2568+
25562569 def get_paths (self ):
25572570 if self ._paths is None :
25582571 self .set_paths ()
@@ -2570,7 +2583,6 @@ def draw(self, renderer):
25702583 if not self .get_visible ():
25712584 return
25722585 renderer .open_group (self .__class__ .__name__ , self .get_gid ())
2573-
25742586 transform = self .get_transform ()
25752587 offset_trf = self .get_offset_transform ()
25762588 offsets = self .get_offsets ()
@@ -2600,34 +2612,19 @@ def draw(self, renderer):
26002612 gc .set_blend_mode (self .get_blend_mode ())
26012613 gc .set_linewidth (self .get_linewidth ()[0 ])
26022614
2603- if self ._shading == 'gouraud' :
2604- triangles , colors = self ._convert_mesh_to_triangles (coordinates )
2605- renderer .draw_gouraud_triangles (
2606- gc , triangles , colors , transform .frozen ())
2607- else :
2608- # If supported by the renderer, draw antialiased patches without strokes
2609- # using the "plus" blend mode in an isolated blend group so that the
2610- # fractional alphas at edges are added to make the intended total alpha.
2611- # If the alphas were instead blended as if they were unrelated opacities,
2612- # the resulting alpha would be smaller (i.e., more transparent), which would
2613- # manifest as slightly transparent line artifacts along patch edges.
2614- isolate = (renderer ._supports_isolated_group_and_plus_blend_mode
2615- and self ._antialiased
2616- and (self ._edgecolors .size == 0 or self ._edgecolors [0 ][3 ] == 0 ))
2617- if isolate :
2618- gc .set_blend_mode ("plus" )
2619- renderer .open_blend_group (self .get_blend_mode ())
2620-
2621- renderer .draw_quad_mesh (
2622- gc , transform .frozen (),
2623- coordinates .shape [1 ] - 1 , coordinates .shape [0 ] - 1 ,
2624- coordinates , offsets , offset_trf ,
2625- # Backends expect flattened rgba arrays (n*m, 4) for fc and ec
2626- self .get_facecolor ().reshape ((- 1 , 4 )),
2627- self ._antialiased , self .get_edgecolors ().reshape ((- 1 , 4 )))
2628-
2629- if isolate :
2630- renderer .close_blend_group ()
2615+ with self ._prep_for_contiguous_drawing (renderer , gc ):
2616+ if self ._shading == 'gouraud' :
2617+ triangles , colors = self ._convert_mesh_to_triangles (coordinates )
2618+ renderer .draw_gouraud_triangles (
2619+ gc , triangles , colors , transform .frozen ())
2620+ else :
2621+ renderer .draw_quad_mesh (
2622+ gc , transform .frozen (),
2623+ coordinates .shape [1 ] - 1 , coordinates .shape [0 ] - 1 ,
2624+ coordinates , offsets , offset_trf ,
2625+ # Backends expect flattened rgba arrays (n*m, 4) for fc and ec
2626+ self .get_facecolor ().reshape ((- 1 , 4 )),
2627+ self ._antialiaseds , self .get_edgecolors ().reshape ((- 1 , 4 )))
26312628 gc .restore ()
26322629 renderer .close_group (self .__class__ .__name__ )
26332630 self .stale = False
0 commit comments