"""Image viewer support"""fromtypingimportList,Optional,Sequence,TYPE_CHECKINGfrommagmap.settingsimportconfigifTYPE_CHECKING:frommatplotlibimportartist,backend_bases,figure_logger=config.logger.getChild(__name__)# inspired by Matplotlib example:# https://matplotlib.org/stable/tutorials/advanced/blitting.html#class-based-example
[docs]classBlitter:"""Controller for blitting in Matplotlib graphics. Improves interactive graphics performance by reducing repetitive drawing. """def__init__(self,fig,artists=None):"""Initialized the blit controller."""#: Matplotlib figure.self.fig:"figure.Figure"=fig#: Internal representation of tracked artists.self._artists=[]self.artists=artists#: Canvas background.self._bkgd=None#: Event listener IDs.self._listeners:List[int]=[fig.canvas.mpl_connect("draw_event",self.on_draw)]@propertydefartists(self)->List["artist.Artist"]:"""Tracked artists for blitting."""returnself._artists@artists.setterdefartists(self,vals:Optional[Sequence["artist.Artist"]]):"""Set tracked artists. Args: vals: Artists to add. Can be None, which will reset artists to an empty list. """ifvalsisNone:# reset artists to empty listself._artists=[]returnforvalinvals:# add artistself.add_artist(val)
[docs]defadd_artist(self,arist:"artist.Artist",i:Optional[int]=None):"""Add tracked artist. Args: arist: Artist to track. Only artists in :attr:`fig` will be added. i: Index at which to add the artist. Defaults to None, which will append the artist. """ifarist.figure!=self.fig:# skip artists in other figs_logger.warn(f"Artist from different figure added for blitting: {arist}")return# flag as animated for update, which appears to prevent updating# non-animated artists as wellarist.set_animated(True)ifiisNone:# append artistself._artists.append(arist)else:# use lower index to position behind other animated artistsself._artists.insert(i,arist)
[docs]defon_draw(self,evt:Optional["backend_bases.DrawEvent"]):"""Recapture backgrouna and draw the figure canvas."""canvas=self.fig.canvasifevtandevt.canvas!=canvas:# skip drawing if event is from another canvasreturn# recapture the canvas background and draw artistsself._bkgd=canvas.copy_from_bbox(self.fig.bbox)self._draw_artists()
[docs]defupdate(self):"""Update the canvas."""canvas=self.fig.canvasifself._bkgdisNone:# get background if not yet setself.on_draw(None)else:# restore saved background, draw artists, and copy to GUI statecanvas.restore_region(self._bkgd)self._draw_artists()canvas.blit(self.fig.bbox)# flush GUI events and repaint if necessarycanvas.flush_events()