@@ -510,6 +510,9 @@ def __init__(self, file):
510510 self .gc = self .new_gc ()
511511 self .fonts = {}
512512
513+ def finalize (self ):
514+ self .gc .finalize ()
515+
513516 def check_gc (self , gc ):
514517 delta = self .gc .delta (gc )
515518 if delta :
@@ -550,7 +553,7 @@ def arc_to_bezier(cx, cy, rx, ry, angle1, sweep):
550553
551554 if sweep < 0.0 :
552555 sweep , angle1 , angle2 = - sweep , angle2 , angle1
553- bp = [ pi / 2.0 * i for i in range (4 ) if pi / 2.0 * i < sweep ]
556+ bp = [ pi / 2.0 * i for i in range (4 ) if pi / 2.0 * i < sweep - epsilon ]
554557 bp .append (sweep )
555558 subarcs = [ arc_to_bezier (x , y , width / 2.0 , height / 2.0 ,
556559 bp [i ], bp [i + 1 ]- bp [i ])
@@ -668,6 +671,7 @@ class GraphicsContextPdf(GraphicsContextBase):
668671 def __init__ (self , file ):
669672 GraphicsContextBase .__init__ (self )
670673 self .file = file
674+ self .parent = None
671675
672676 capstyles = { 'butt' : 0 , 'round' : 1 , 'projecting' : 2 }
673677 joinstyles = { 'miter' : 0 , 'round' : 1 , 'bevel' : 2 }
@@ -694,6 +698,24 @@ def rgb_cmd(self, rgb):
694698 rgb = tmap (pdfRepr , rgb )
695699 return ('%s %s %s RG ' % rgb ) + ('%s %s %s rg' % rgb )
696700
701+ def push (self ):
702+ parent = GraphicsContextPdf (self .file )
703+ parent .copy_properties (self )
704+ parent .parent = self .parent
705+ self .parent = parent
706+ return 'q'
707+
708+ def pop (self ):
709+ assert self .parent is not None
710+ self .copy_properties (self .parent )
711+ self .parent = self .parent .parent
712+ return 'Q'
713+
714+ def cliprect_cmd (self , cliprect ):
715+ """Set clip rectangle. Can only be undone by popping the graphics
716+ state; thus needs to be enclosed in a push/pop pair."""
717+ return "%s %s %s %s re W n" % tmap (pdfRepr , cliprect )
718+
697719 commands = {
698720 '_alpha' : alpha_cmd ,
699721 '_capstyle' : capstyle_cmd ,
@@ -703,20 +725,30 @@ def rgb_cmd(self, rgb):
703725 '_rgb' : rgb_cmd ,
704726 }
705727
706- # TODO: _cliprect, _linestyle, _hatch
707- # _cliprect needs pushing/popping the graphics state,
708- # probably needs to be done in RendererPdf
728+ # TODO: _linestyle, _hatch
709729
710730 def delta (self , other ):
711731 """What PDF commands are needed to transform self into other?
712732 """
713733 cmds = []
734+ if self ._cliprect != other ._cliprect and self .parent is not None :
735+ cmds .append (self .pop ())
736+ if self ._cliprect != other ._cliprect :
737+ cmds .append (self .push ())
738+ cmds .append (self .cliprect_cmd (other ._cliprect ))
739+
714740 for param in self .commands .keys ():
715741 if getattr (self , param ) != getattr (other , param ):
716742 cmd = self .commands [param ]
717743 cmds .append (cmd (self , getattr (other , param )))
718744 return '\n ' .join (cmds )
719745
746+ def finalize (self ):
747+ """Make sure every pushed graphics state is popped."""
748+ cmds = []
749+ while self .parent is not None :
750+ cmds .append (self .pop ())
751+ return '\n ' .join (cmds )
720752
721753########################################################################
722754#
@@ -777,6 +809,7 @@ def print_figure(self, filename, dpi=72, facecolor='w', edgecolor='w',
777809 file = PdfFile (width , height , filename )
778810 renderer = RendererPdf (file )
779811 self .figure .draw (renderer )
812+ renderer .finalize ()
780813 file .close ()
781814
782815class FigureManagerPdf (FigureManagerBase ):
0 commit comments