Responding to my own very old thread…
For some reason, now that I have upgraded last week to wxPython 4.1.0 and Matplotlib 2.2.5 (from previously a wxPython wxPython 3.0.2.0 and Matplotlib 1.1.3), I’m having this same problem again as I had years back.
The problem is the same as listed in the original thread: When I go to zoom in on a Matplotlib graph, the “rubberband” doesn’t show. This was originally due to my using SetCompositeMode() on the frame that this Matplotlib canvas is ultimately within, which means ClientDC isn’t shown. As Robin said:
Yes, setting DoubleBuffered/Composite mode on Windows can make it so drawing done via a wx.ClientDC is lost and never actually seen. You really need to do all drawing in the paint event in that case, or use wx.Overlay for transient drawing.
However, it was working last week before I upgraded wxPython and Matplotlib. I’m not sure what changed and what I need to do.
It seems I need to keep the SetCompositeMode() on the frame because if I don’t, I get some ugly black/damaged areas in the page of the aui.AuiNotebook. But maybe not anymore? Any other way to avoid this damage?
Below I will give the code for the draw_rubberband function in Matplotlib 1.1.3 and now the new one I am using in 2.2.5.
Robin, can you suggest what I can do? Thanks!
Matplotlib 1.1.3’s draw_rubberband function:
def draw_rubberband(self, event, x0, y0, x1, y1):
'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744'
canvas = self.canvas
dc =wx.ClientDC(canvas)
# Set logical function to XOR for rubberbanding
dc.SetLogicalFunction(wx.XOR)
# Set dc brush and pen
# Here I set brush and pen to white and grey respectively
# You can set it to your own choices
# The brush setting is not really needed since we
# dont do any filling of the dc. It is set just for
# the sake of completion.
wbrush =wx.Brush(wx.Colour(255,255,255), wx.TRANSPARENT)
wpen =wx.Pen(wx.Colour(200, 200, 200), 1, wx.SOLID)
dc.SetBrush(wbrush)
dc.SetPen(wpen)
dc.ResetBoundingBox()
dc.BeginDrawing()
height = self.canvas.figure.bbox.height
y1 = height - y1
y0 = height - y0
if y1<y0: y0, y1 = y1, y0
if x1<y0: x0, x1 = x1, x0
w = x1 - x0
h = y1 - y0
rect = int(x0), int(y0), int(w), int(h)
try: lastrect = self.lastrect
except AttributeError: pass
else: dc.DrawRectangle(*lastrect) #erase last
self.lastrect = rect
dc.DrawRectangle(*rect)
dc.EndDrawing()
Matplotlib 2.2.5’s draw_rubberband function:
def draw_rubberband(self, event, x0, y0, x1, y1):
if self.retinaFix: # On Macs, use the following code
# wx.DCOverlay does not work properly on Retina displays.
rubberBandColor = '#db1818' #'#C0C0FF'
if self.prevZoomRect:
self.prevZoomRect.pop(0).remove()
self.canvas.restore_region(self.savedRetinaImage)
X0, X1 = self.zoomStartX, event.xdata
Y0, Y1 = self.zoomStartY, event.ydata
lineX = (X0, X0, X1, X1, X0)
lineY = (Y0, Y1, Y1, Y0, Y0)
self.prevZoomRect = self.zoomAxes.plot(
lineX, lineY, '-', color=rubberBandColor)
self.zoomAxes.draw_artist(self.prevZoomRect[0])
self.canvas.blit(self.zoomAxes.bbox)
return
# Use an Overlay to draw a rubberband-like bounding box.
dc = wx.ClientDC(self.canvas)
odc = wx.DCOverlay(self.wxoverlay, dc)
odc.Clear()
# Mac's DC is already the same as a GCDC, and it causes
# problems with the overlay if we try to use an actual
# wx.GCDC so don't try it.
if 'wxMac' not in wx.PlatformInfo:
dc = wx.GCDC(dc)
height = self.canvas.figure.bbox.height
y1 = height - y1
y0 = height - y0
if y1 < y0:
y0, y1 = y1, y0
if x1 < x0:
x0, x1 = x1, x0
w = x1 - x0
h = y1 - y0
rect = wx.Rect(x0, y0, w, h)
rubberBandColor = '#db1818' #'#C0C0FF' # or load from config?
# Set a pen for the border
color = wxc.NamedColour(rubberBandColor)
dc.SetPen(wx.Pen(color, 1))
# use the same color, plus alpha for the brush
r, g, b, a = color.Get(True)
color.Set(r, g, b, 0x60)
dc.SetBrush(wx.Brush(color))
if wxc.is_phoenix:
dc.DrawRectangle(rect)
else:
dc.DrawRectangleRect(rect)
···