📄 ownomogramgraph.py
字号:
#brush.setStyle()
self.setBrush(brush)
else:
self.setBrush(QBrush(self.brush().color()))
def showSelected(self):
#self.borderCircle.show()
self.setBrush(QBrush(QColor(253,151,51), self.brush().style()))
if self.canvas().parent.bubble:
self.descriptor.showAll()
def hideSelected(self):
#self.borderCircle.hide()
self.setBrush(QBrush(Qt.blue, self.brush().style()))
self.descriptor.hideAll()
# ####################################################################
# Single Attribute Value
# ####################################################################
class AttValue:
def __init__(self, name, betaValue, error=0, showErr=False, over=True, lineWidth = 0, markerWidth = 2, enable = True):
self.name = name
self.betaValue = betaValue
self.error = error
self.showErr = showErr
self.enable = enable
self.hideAtValue = False
self.over = over
self.lineWidth = lineWidth
self.markerWidth = markerWidth
self.attCreation = True # flag shows that vanvas object have to be created first
def destroy(self):
if not self.attCreation:
self.hide()
def setCreation(self, canvas):
self.text = QCanvasText(self.name, canvas)
self.text.setTextFlags(Qt.AlignCenter)
self.labelMarker = QCanvasLine(canvas)
self.labelMarker.setPen(QPen(Qt.black, self.markerWidth))
self.histogram = QCanvasLine(canvas)
self.histogram.setZ(HISTOGRAM_Z)
self.histogram.setPen(QPen(QColor(140,140,140),7))
self.errorLine = QCanvasLine(canvas)
self.errorLine.setPen(QPen(QColor(25,25,255),1))
self.errorLine.setZ(SE_Z)
self.attCreation = False
def hide(self):
self.text.hide()
self.labelMarker.hide()
self.errorLine.hide()
def paint(self, canvas, rect, mapper):
def errorCollision(line,z=SE_Z):
col = filter(lambda x:x.z()==z,line.collisions(True))
if len(col)>0:
return True
return False
if self.attCreation:
self.setCreation(canvas)
self.text.setX(self.x)
if self.enable:
lineLength = canvas.fontSize/2
canvasLength = 0
if canvas.parent.histogram and isinstance(canvas, BasicNomogram):
canvasLength = 2+self.lineWidth*canvas.parent.histogram_size
if self.over:
self.text.setY(rect.bottom()-4*canvas.fontSize/3)
self.labelMarker.setPoints(self.x, rect.bottom(), self.x, rect.bottom()+lineLength)
self.histogram.setPoints(self.x, rect.bottom(), self.x, rect.bottom()+canvasLength)
else:
self.text.setY(rect.bottom()+4*canvas.fontSize/3)
self.labelMarker.setPoints(self.x, rect.bottom(), self.x, rect.bottom()-lineLength)
self.histogram.setPoints(self.x, rect.bottom(), self.x, rect.bottom()-canvasLength)
if not self.hideAtValue:
self.text.show()
else:
self.text.hide()
if canvas.parent.histogram:
self.histogram.show()
# else:
# self.histogram.hide()
# if value is disabled, draw just a symbolic line
else:
self.labelMarker.setPoints(self.x, rect.bottom(), self.x, rect.bottom()+canvas.fontSize/4)
self.text.hide()
# show confidence interval
if self.showErr:
self.low_errorX = max(self.low_errorX, 0)
self.high_errorX = min(self.high_errorX, canvas.size().width())
if self.low_errorX == 0 and self.high_errorX == canvas.size().width():
self.errorLine.setPen(QPen(self.errorLine.pen().color(),self.errorLine.pen().width(),Qt.DotLine))
else:
self.errorLine.setPen(QPen(self.errorLine.pen().color(), self.errorLine.pen().width()))
if self.over:
add = 2
n=0
self.errorLine.setPoints(self.low_errorX, rect.bottom()+add, self.high_errorX , rect.bottom()+add)
while errorCollision(self.errorLine):
n=n+1
if add>0:
add = -add
else:
add = -add + 2
self.errorLine.setPoints(self.low_errorX, rect.bottom()+add, self.high_errorX , rect.bottom()+add)
else:
add = -2
self.errorLine.setPoints(self.low_errorX, rect.bottom()+add, self.high_errorX , rect.bottom()+add)
while errorCollision(self.errorLine):
if add<0:
add = -add
else:
add = -add - 2
self.errorLine.setPoints(self.low_errorX, rect.bottom()+add, self.high_errorX , rect.bottom()+add)
self.errorLine.show()
self.labelMarker.show()
def toString(self):
return self.name, "beta =", self.betaValue
# ####################################################################
# Normal attribute - 1d
# ####################################################################
# This is a base class for representing all different possible attributes in nomogram.
# Use it only for discrete/non-ordered values
class AttrLine:
def __init__(self, name, canvas):
self.name = name
self.attValues = []
self.minValue = self.maxValue = 0
self.selectedValue = None
self.initialize(canvas)
def addAttValue(self, attValue):
if len(self.attValues)==0:
self.minValue = attValue.betaValue
self.maxValue = attValue.betaValue
else:
self.minValue = min(self.minValue, attValue.betaValue)
self.maxValue = max(self.maxValue, attValue.betaValue)
self.attValues.append(attValue)
def getHeight(self, canvas):
return canvas.parent.verticalSpacing
# Find the closest (selectable) point to mouse-clicked one.
def updateValueXY(self, x, y):
oldSelect = self.selectedValue
minXDiff = 50
minYDiff = 50
minAbs = 100
for xyCanvas in self.selectValues:
if (abs(x-xyCanvas[0]) + abs(y-xyCanvas[1]))<minAbs:
self.selectedValue = xyCanvas
minYDiff = abs(y-xyCanvas[1])
minXDiff = abs(x-xyCanvas[0])
minAbs = minYDiff + minXDiff
if oldSelect == self.selectedValue:
return False
else:
self.marker.setPos(self.selectedValue[0], self.selectedValue[1])
return True
# Update position of the marker!
# This is usualy necessary after changing types of nomogram, for example left-aligned to center-aligned.
# In this situations selected beta should stay the same, but x an y of the marker must change!
def updateValue(self):
if not self.selectedValue:
return
beta = self.selectedValue[2]
minBetaDiff = 1
for xyCanvas in self.selectValues:
if abs(beta-xyCanvas[2])<minBetaDiff:
self.selectedValue = xyCanvas
minBetaDiff = abs(beta-xyCanvas[2])
self.marker.setPos(self.selectedValue[0], self.selectedValue[1])
def initialize(self, canvas):
self.label = QCanvasText(canvas)
self.label.setText(self.name)
font = QFont(self.label.font())
font.setBold(True)
self.label.setFont(font) # draw label in bold
self.line = QCanvasLine(canvas)
# create blue probability marker
self.marker = AttValueMarker(self, canvas, 50)
def drawAttributeLine(self, canvas, rect, mapper):
atValues_mapped, atErrors_mapped, min_mapped, max_mapped = mapper(self, error_factor = norm_factor(1-((1-float(canvas.parent.confidence_percent)/100.)/2.))) # return mapped values, errors, min, max --> mapper(self)
self.label.setX(1)
self.label.setY(rect.bottom()-canvas.fontSize)
# draw attribute line
self.line.setPoints(min_mapped, rect.bottom(), max_mapped, rect.bottom())
zero = 0
if len([at.betaValue for at in self.attValues]) == 0:
return
if min([at.betaValue for at in self.attValues])>0:
zero = min([at.betaValue for at in self.attValues])
if max([at.betaValue for at in self.attValues])<0:
zero = max([at.betaValue for at in self.attValues])
self.selectValues = [[mapper.mapBeta(zero, self), rect.bottom(), zero]]
if not self.selectedValue:
self.selectedValue = self.selectValues[0]
def paint(self, canvas, rect, mapper):
self.label.setText(self.name)
atValues_mapped, atErrors_mapped, min_mapped, max_mapped = mapper(self, error_factor = norm_factor(1-((1-float(canvas.parent.confidence_percent)/100.)/2.))) # return mapped values, errors, min, max --> mapper(self)
self.drawAttributeLine(canvas, rect, mapper)
# draw attributes
val = self.attValues
# draw values
for i in range(len(val)):
# check attribute name that will not cover another name
val[i].x = atValues_mapped[i]
val[i].high_errorX = atErrors_mapped[i][1]
val[i].low_errorX = atErrors_mapped[i][0]
a = time.time()
if canvas.parent.confidence_check and val[i].error>0:
val[i].showErr = True
else:
val[i].showErr = False
val[i].hideAtValue = False
val[i].over = True
val[i].paint(canvas, rect, mapper)
#find suitable value position
for j in range(i):
#if val[j].over and val[j].enable and abs(atValues_mapped[j]-atValues_mapped[i])<(len(val[j].name)*canvas.fontSize/4+len(val[i].name)*canvas.fontSize/4):
if val[j].over and val[j].enable and not val[j].hideAtValue and val[j].text.collidesWith(val[i].text):
val[i].over = False
if not val[i].over:
val[i].paint(canvas, rect, mapper)
for j in range(i):
if not val[j].over and val[j].enable and not val[j].hideAtValue and val[j].text.collidesWith(val[i].text):
val[i].hideAtValue = True
if val[i].hideAtValue:
val[i].paint(canvas, rect, mapper)
self.selectValues.append([atValues_mapped[i], rect.bottom(), val[i].betaValue])
atLine = AttrLine("marker", canvas)
d = 5*(self.maxValue-self.minValue)/max((max_mapped-min_mapped),aproxZero)
for xc in Numeric.arange(self.minValue, self.maxValue+d, d):
atLine.addAttValue(AttValue("", xc))
markers_mapped, mark_errors_mapped, markMin_mapped, markMax_mapped = mapper(atLine)
for mar in range(len(markers_mapped)):
xVal = markers_mapped[mar]
if filter(lambda x: abs(x[0]-xVal)<4, self.selectValues) == [] and xVal<max_mapped:
self.selectValues.append([xVal, rect.bottom(), atLine.attValues[mar].betaValue])
self.updateValue()
if max_mapped - min_mapped > 5.0:
self.line.show()
self.label.show()
# some supplementary methods for 2d presentation
# draw bounding box around cont. attribute
def drawBox(self, min_mapped, max_mapped, rect):
# draw box
self.box.setX(min_mapped)
self.box.setY(rect.top()+rect.height()/8)
self.box.setSize(max_mapped-min_mapped, rect.height()*7/8)
# show att. name
self.label.setText(self.name)
self.label.setX(min_mapped)
self.label.setY(rect.top()+rect.height()/8)
# draws a vertical legend on the left side of the bounding box
def drawVerticalLabel(self, attLineLabel, min_mapped, mapped_labels, canvas):
for at in range(len(attLineLabel.attValues)):
# draw value
a = self.contLabel[at]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -