📄 plot.py
字号:
height = self._Buffer.GetHeight()
tmp_Buffer = wx.EmptyBitmap(width,height)
dcs = wx.MemoryDC()
dcs.SelectObject(tmp_Buffer)
dcs.Clear()
dcs.BeginDrawing()
self._pointLabelFunc(dcs,mDataDict) #custom user pointLabel function
dcs.EndDrawing()
dc = wx.ClientDC( self.canvas )
#this will erase if called twice
dc.Blit(0, 0, width, height, dcs, 0, 0, wx.EQUIV) #(NOT src) XOR dst
def _drawLegend(self,dc,graphics,rhsW,topH,legendBoxWH, legendSymExt, legendTextExt):
"""Draws legend symbols and text"""
# top right hand corner of graph box is ref corner
trhc= self.plotbox_origin+ (self.plotbox_size-[rhsW,topH])*[1,-1]
legendLHS= .091* legendBoxWH[0] # border space between legend sym and graph box
lineHeight= max(legendSymExt[1], legendTextExt[1]) * 1.1 #1.1 used as space between lines
dc.SetFont(self._getFont(self._fontSizeLegend))
for i in range(len(graphics)):
o = graphics[i]
s= i*lineHeight
if isinstance(o,PolyMarker):
# draw marker with legend
pnt= (trhc[0]+legendLHS+legendSymExt[0]/2., trhc[1]+s+lineHeight/2.)
o.draw(dc, self.printerScale, coord= _Numeric.array([pnt]))
elif isinstance(o,PolyLine):
# draw line with legend
pnt1= (trhc[0]+legendLHS, trhc[1]+s+lineHeight/2.)
pnt2= (trhc[0]+legendLHS+legendSymExt[0], trhc[1]+s+lineHeight/2.)
o.draw(dc, self.printerScale, coord= _Numeric.array([pnt1,pnt2]))
else:
raise TypeError, "object is neither PolyMarker or PolyLine instance"
# draw legend txt
pnt= (trhc[0]+legendLHS+legendSymExt[0], trhc[1]+s+lineHeight/2.-legendTextExt[1]/2)
dc.DrawText(o.getLegend(),pnt[0],pnt[1])
dc.SetFont(self._getFont(self._fontSizeAxis)) # reset
def _titleLablesWH(self, dc, graphics):
"""Draws Title and labels and returns width and height for each"""
# TextExtents for Title and Axis Labels
dc.SetFont(self._getFont(self._fontSizeTitle))
title= graphics.getTitle()
titleWH= dc.GetTextExtent(title)
dc.SetFont(self._getFont(self._fontSizeAxis))
xLabel, yLabel= graphics.getXLabel(),graphics.getYLabel()
xLabelWH= dc.GetTextExtent(xLabel)
yLabelWH= dc.GetTextExtent(yLabel)
return titleWH, xLabelWH, yLabelWH
def _legendWH(self, dc, graphics):
"""Returns the size in screen units for legend box"""
if self._legendEnabled != True:
legendBoxWH= symExt= txtExt= (0,0)
else:
# find max symbol size
symExt= graphics.getSymExtent(self.printerScale)
# find max legend text extent
dc.SetFont(self._getFont(self._fontSizeLegend))
txtList= graphics.getLegendNames()
txtExt= dc.GetTextExtent(txtList[0])
for txt in graphics.getLegendNames()[1:]:
txtExt= _Numeric.maximum(txtExt,dc.GetTextExtent(txt))
maxW= symExt[0]+txtExt[0]
maxH= max(symExt[1],txtExt[1])
# padding .1 for lhs of legend box and space between lines
maxW= maxW* 1.1
maxH= maxH* 1.1 * len(txtList)
dc.SetFont(self._getFont(self._fontSizeAxis))
legendBoxWH= (maxW,maxH)
return (legendBoxWH, symExt, txtExt)
def _drawRubberBand(self, corner1, corner2):
"""Draws/erases rect box from corner1 to corner2"""
ptx,pty,rectWidth,rectHeight= self._point2ClientCoord(corner1, corner2)
# draw rectangle
dc = wx.ClientDC( self.canvas )
dc.BeginDrawing()
dc.SetPen(wx.Pen(wx.BLACK))
dc.SetBrush(wx.Brush( wx.WHITE, wx.TRANSPARENT ) )
dc.SetLogicalFunction(wx.INVERT)
dc.DrawRectangle( ptx,pty, rectWidth,rectHeight)
dc.SetLogicalFunction(wx.COPY)
dc.EndDrawing()
def _getFont(self,size):
"""Take font size, adjusts if printing and returns wx.Font"""
s = size*self.printerScale
of = self.GetFont()
# Linux speed up to get font from cache rather than X font server
key = (int(s), of.GetFamily (), of.GetStyle (), of.GetWeight ())
font = self._fontCache.get (key, None)
if font:
return font # yeah! cache hit
else:
font = wx.Font(int(s), of.GetFamily(), of.GetStyle(), of.GetWeight())
self._fontCache[key] = font
return font
def _point2ClientCoord(self, corner1, corner2):
"""Converts user point coords to client screen int coords x,y,width,height"""
c1= _Numeric.array(corner1)
c2= _Numeric.array(corner2)
# convert to screen coords
pt1= c1*self._pointScale+self._pointShift
pt2= c2*self._pointScale+self._pointShift
# make height and width positive
pul= _Numeric.minimum(pt1,pt2) # Upper left corner
plr= _Numeric.maximum(pt1,pt2) # Lower right corner
rectWidth, rectHeight= plr-pul
ptx,pty= pul
return ptx, pty, rectWidth, rectHeight
def _axisInterval(self, spec, lower, upper):
"""Returns sensible axis range for given spec"""
if spec == 'none' or spec == 'min':
if lower == upper:
return lower-0.5, upper+0.5
else:
return lower, upper
elif spec == 'auto':
range = upper-lower
if range == 0.:
return lower-0.5, upper+0.5
log = _Numeric.log10(range)
power = _Numeric.floor(log)
fraction = log-power
if fraction <= 0.05:
power = power-1
grid = 10.**power
lower = lower - lower % grid
mod = upper % grid
if mod != 0:
upper = upper - mod + grid
return lower, upper
elif type(spec) == type(()):
lower, upper = spec
if lower <= upper:
return lower, upper
else:
return upper, lower
else:
raise ValueError, str(spec) + ': illegal axis specification'
def _drawAxes(self, dc, p1, p2, scale, shift, xticks, yticks):
penWidth= self.printerScale # increases thickness for printing only
dc.SetPen(wx.Pen(self._gridColour, penWidth))
# set length of tick marks--long ones make grid
if self._gridEnabled:
x,y,width,height= self._point2ClientCoord(p1,p2)
if self._gridEnabled == 'Horizontal':
yTickLength= width/2.0 +1
xTickLength= 3 * self.printerScale
elif self._gridEnabled == 'Vertical':
yTickLength= 3 * self.printerScale
xTickLength= height/2.0 +1
else:
yTickLength= width/2.0 +1
xTickLength= height/2.0 +1
else:
yTickLength= 3 * self.printerScale # lengthens lines for printing
xTickLength= 3 * self.printerScale
if self._xSpec is not 'none':
lower, upper = p1[0],p2[0]
text = 1
for y, d in [(p1[1], -xTickLength), (p2[1], xTickLength)]: # miny, maxy and tick lengths
a1 = scale*_Numeric.array([lower, y])+shift
a2 = scale*_Numeric.array([upper, y])+shift
dc.DrawLine(a1[0],a1[1],a2[0],a2[1]) # draws upper and lower axis line
for x, label in xticks:
pt = scale*_Numeric.array([x, y])+shift
dc.DrawLine(pt[0],pt[1],pt[0],pt[1] + d) # draws tick mark d units
if text:
dc.DrawText(label,pt[0],pt[1])
text = 0 # axis values not drawn on top side
if self._ySpec is not 'none':
lower, upper = p1[1],p2[1]
text = 1
h = dc.GetCharHeight()
for x, d in [(p1[0], -yTickLength), (p2[0], yTickLength)]:
a1 = scale*_Numeric.array([x, lower])+shift
a2 = scale*_Numeric.array([x, upper])+shift
dc.DrawLine(a1[0],a1[1],a2[0],a2[1])
for y, label in yticks:
pt = scale*_Numeric.array([x, y])+shift
dc.DrawLine(pt[0],pt[1],pt[0]-d,pt[1])
if text:
dc.DrawText(label,pt[0]-dc.GetTextExtent(label)[0],
pt[1]-0.5*h)
text = 0 # axis values not drawn on right side
def _xticks(self, *args):
if self._logscale[0]:
return self._logticks(*args)
else:
return self._ticks(*args)
def _yticks(self, *args):
if self._logscale[1]:
return self._logticks(*args)
else:
return self._ticks(*args)
def _logticks(self, lower, upper):
#lower,upper = map(_Numeric.log10,[lower,upper])
#print 'logticks',lower,upper
ticks = []
mag = _Numeric.power(10,_Numeric.floor(lower))
if upper-lower > 6:
t = _Numeric.power(10,_Numeric.ceil(lower))
base = _Numeric.power(10,_Numeric.floor((upper-lower)/6))
def inc(t):
return t*base-t
else:
t = _Numeric.ceil(_Numeric.power(10,lower)/mag)*mag
def inc(t):
return 10**int(_Numeric.floor(_Numeric.log10(t)+1e-16))
majortick = int(_Numeric.log10(mag))
while t <= pow(10,upper):
if majortick != int(_Numeric.floor(_Numeric.log10(t)+1e-16)):
majortick = int(_Numeric.floor(_Numeric.log10(t)+1e-16))
ticklabel = '1e%d'%majortick
else:
if upper-lower < 2:
minortick = int(t/pow(10,majortick)+.5)
ticklabel = '%de%d'%(minortick,majortick)
else:
ticklabel = ''
ticks.append((_Numeric.log10(t), ticklabel))
t += inc(t)
if len(ticks) == 0:
ticks = [(0,'')]
return ticks
def _ticks(self, lower, upper):
ideal = (upper-lower)/7.
log = _Numeric.log10(ideal)
power = _Numeric.floor(log)
fraction = log-power
factor = 1.
error = fraction
for f, lf in self._multiples:
e = _Numeric.fabs(fraction-lf)
if e < error:
error = e
factor = f
grid = factor * 10.**power
if power > 4 or power < -4:
format = '%+7.1e'
elif power >= 0:
digits = max(1, int(power))
format = '%' + `digits`+'.0f'
else:
digits = -int(power)
format = '%'+`digits+2`+'.'+`digits`+'f'
ticks = []
t = -grid*_Numeric.floor(-lower/grid)
while t <= upper:
ticks.append( (t, format % (t,)) )
t = t + grid
return ticks
_multiples = [(2., _Numeric.log10(2.)), (5., _Numeric.log10(5.))]
def _adjustScrollbars(self):
if self._sb_ignore:
self._sb_ignore = False
return
self._adjustingSB = True
needScrollbars = False
# horizontal scrollbar
r_current = self._getXCurrentRange()
r_max = list(self._getXMaxRange())
sbfullrange = float(self.sb_hor.GetRange())
r_max[0] = min(r_max[0],r_current[0])
r_max[1] = max(r_max[1],r_current[1])
self._sb_xfullrange = r_max
unit = (r_max[1]-r_max[0])/float(self.sb_hor.GetRange())
pos = int((r_current[0]-r_max[0])/unit)
if pos >= 0:
pagesize = int((r_current[1]-r_current[0])/unit)
self.sb_hor.SetScrollbar(pos, pagesize, sbfullrange, pagesize)
self._sb_xunit = unit
needScrollbars = needScrollbars or (pagesize != sbfullrange)
else:
self.sb_hor.SetScrollbar(0, 1000, 1000, 1000)
# vertical scrollbar
r_current = self._getYCurrentRange()
r_max = list(self._getYMaxRange())
sbfullrange = float(self.sb_vert.GetRange())
r_max[0] = min(r_max[0],r_current[0])
r_max[1] = max(r_max[1],r_current[1])
self._sb_yfullrange = r_max
unit = (r_max[1]-r_max[0])/sbfullrange
pos = int((r_current[0]-r_max[0])/unit)
if pos >= 0:
pagesize = int((r_current[1]-r_current[0])/unit)
pos = (sbfullrange-1-pos-pagesize)
self.sb_vert.SetScrollbar(pos, pagesize, sbfullrange, pagesize)
self._sb_yunit = unit
needScrollbars = needScrollbars or (pagesize != sbfullrange)
else:
self.sb_vert.SetScrollbar(0, 1000, 1000, 1000)
self.SetShowScrollbars(needScrollbars)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -