📄 ownomogramgraph.py
字号:
mapped_labels = [self.getVerticalCoordinates(rect,v)-canvas.fontSize/2 for v in self.attValues]
self.drawVerticalLabel(self, min_mapped, mapped_labels, canvas)
#find and select zero value (beta = 0)
(propBeta,maxPos,zero) = self.findZeroValue()
self.selectValues = [[mapper.mapBeta(zero, self),self.getVerticalCoordinates(rect, self.attValues[maxPos-1]), zero]]
if not self.selectedValue:
self.selectedValue = self.selectValues[0]
# draw lines
for i in range(len(atValues_mapped)):
a = self.contValues[i]
if canvas.parent.histogram:
a.setPen(QPen(Qt.black, 1+self.attValues[i].lineWidth*canvas.parent.histogram_size))
else:
a.setPen(QPen(Qt.black, 2))
a.setPoints(atValues_mapped[i], self.getVerticalCoordinates(rect, self.attValues[i])-canvas.parent.diff_between_ordinal/2, atValues_mapped[i], self.getVerticalCoordinates(rect, self.attValues[i])+canvas.parent.diff_between_ordinal/2)
self.selectValues.append([atValues_mapped[i],self.getVerticalCoordinates(rect, self.attValues[i]), self.attValues[i].betaValue])
if i < len(atValues_mapped)-1:
a.connection = QCanvasLine(canvas)
a.connection.setPen(QPen(Qt.black, 1))
a.connection.setPoints(atValues_mapped[i],
self.getVerticalCoordinates(rect, self.attValues[i])-canvas.parent.diff_between_ordinal/2,
atValues_mapped[i+1],
self.getVerticalCoordinates(rect, self.attValues[i])-canvas.parent.diff_between_ordinal/2)
a.connection.setPen(QPen(Qt.DotLine))
a.connection.show()
# if distance between i and i+1 is large, add some select values.
x1 = atValues_mapped[i]
y1 = self.getVerticalCoordinates(rect, self.attValues[i])-canvas.parent.diff_between_ordinal/2
x2 = atValues_mapped[i]
y2 = self.getVerticalCoordinates(rect, self.attValues[i])+canvas.parent.diff_between_ordinal/2
n = int(y2-y1)/5-1
self.selectValues = self.selectValues + [[x1, y1+(float(j+1)/float(n+1))*(y2-y1), self.attValues[i].betaValue] for j in range(n)]
a.show()
def paint2d(self, canvas, rect, mapper):
self.initializeBeforePaint(canvas)
# get all values tranfsormed with current mapper
atValues_mapped, atErrors_mapped, min_mapped, max_mapped = mapper(self) # return mapped values, errors, min, max --> mapper(self)
# draw a bounding box
self.drawBox(min_mapped, max_mapped+1, rect)
# if fixedDistance:
self.paint2d_fixedDistance(canvas, rect, mapper)
self.updateValue()
self.box.show()
self.label.show()
# ####################################################################
# Header CANVAS
# ####################################################################
class BasicNomogramHeader(QCanvas):
def __init__(self, nomogram, parent):
apply(QCanvas.__init__,(self, parent, ""))
self.fontSize = parent.fontSize
self.headerAttrLine = None
self.nomogram = nomogram
self.parent = parent
def paintHeader(self, rect, mapper):
#if self.headerAttrLine:
# self.headerAttrLine.destroy()
[item.setCanvas(None) for item in self.allItems()]
self.headerAttrLine = mapper.getHeaderLine(self, rect)
self.headerAttrLine.name = self.nomogram.parent.pointsName[self.nomogram.parent.yAxis]
self.headerAttrLine.paint(self, rect, mapper)
self.resize(self.nomogram.pright, rect.height()+16)
self.update()
# ####################################################################
# FOOTER CANVAS, sum and probability
# ####################################################################
class BasicNomogramFooter(QCanvas):
def __init__(self, nomogram, parent):
apply(QCanvas.__init__,(self, parent, ""))
self.fontSize = parent.fontSize
self.headerAttrLine = None
self.nomogram = nomogram
self.footer = None
self.footerPercent = None
self.parent = parent
if self.parent.cl:
self.footerPercentName = "P(%s=\"%s\")" % (self.parent.cl.domain.classVar.name,self.parent.cl.domain.classVar.values[self.parent.TargetClassIndex])
else:
self.footerPercentName = ""
self.connectedLine = QCanvasLine(self)
self.connectedLine.setPen(QPen(Qt.blue))
self.errorLine = QCanvasLine(self)
self.errorPercentLine = QCanvasLine(self)
self.leftArc = QCanvasPolygon(self)
self.rightArc = QCanvasPolygon(self)
self.leftPercentArc = QCanvasPolygon(self)
self.rightPercentArc = QCanvasPolygon(self)
self.cilist = [self.errorLine, self.errorPercentLine, self.leftArc, self.rightArc, self.leftPercentArc, self.rightPercentArc]
for obj in self.cilist:
obj.setPen(QPen(Qt.blue, 3))
obj.setZ(100)
def convertToPercent(self, atLine):
minPercent = math.exp(atLine.minValue)/(1+math.exp(atLine.minValue))
maxPercent = math.exp(atLine.maxValue)/(1+math.exp(atLine.maxValue))
percentLine = AttrLine(atLine.name, self)
percentList = filter(lambda x:x>minPercent and x<maxPercent,Numeric.arange(0, maxPercent+0.1, 0.05))
for p in percentList:
if int(10*p) != round(10*p,1) and not p == percentList[0] and not p==percentList[len(percentList)-1]:
percentLine.addAttValue(AttValue(" "+str(p)+" ", math.log(p/max(1-p,aproxZero)), markerWidth = 1, enable = False))
else:
percentLine.addAttValue(AttValue(" "+str(p)+" ", math.log(p/max(1-p,aproxZero)), markerWidth = 1))
return percentLine
def paintFooter(self, rect, alignType, yAxis, mapper):
# set height for each scale
height = rect.height()/3
# get min and maximum sum, min and maximum beta
# min beta <--> min sum! , same for maximum
maxSum = minSum = maxSumBeta = minSumBeta = 0
for at in self.nomogram.attributes:
maxSum += mapper.getMaxValue(at)
minSum += mapper.getMinValue(at)
maxSumBeta += at.maxValue
minSumBeta += at.minValue
# add constant to betas!
maxSumBeta += self.nomogram.constant.betaValue
minSumBeta += self.nomogram.constant.betaValue
# show only reasonable values
k = (maxSum-minSum)/max((maxSumBeta-minSumBeta),aproxZero)
if maxSumBeta>4:
maxSum = (4 - minSumBeta)*k + minSum
maxSumBeta = 4
if minSumBeta>3:
minSum = (3 - minSumBeta)*k + minSum
minSumBeta = 3
if minSumBeta<-4:
minSum = (-4 - minSumBeta)*k + minSum
minSumBeta = -4
if maxSumBeta<-3:
maxSum = (-3 - minSumBeta)*k + minSum
maxSumBeta = -3
# draw continous line with values from min and max sum (still have values!)
self.m = Mapper_Linear_Fixed(minSumBeta, maxSumBeta, rect.left(), rect.right(), maxLinearValue = maxSum, minLinearValue = minSum)
if self.footer:
[item.setCanvas(None) for item in self.allItems()]
#self.footer.destroy()
self.footer = self.m.getHeaderLine(self, QRect(rect.left(), rect.top(), rect.width(), height))
self.footer.name = self.nomogram.parent.totalPointsName[self.nomogram.parent.yAxis]
self.footer.paint(self, QRect(rect.left(), rect.top(), rect.width(), height), self.m)
# continous line convert to percent and draw accordingly (minbeta = minsum)
#if self.footerPercent:
# self.footerPercent.destroy()
self.footerPercent = self.convertToPercent(self.footer)
# create a mapper for footer, BZ CHANGE TO CONSIDER THE TARGET
self.footerPercent.name = self.footerPercentName
self.footerPercent.paint(self, QRect(rect.left(), rect.top()+height, rect.width(), 2*height), self.m)
self.resize(self.nomogram.pright, rect.height()+30)
self.update()
def updateMarkers(self):
# finds neares beta; use only discrete data
def getNearestAtt(selectedBeta, at):
nearestLeft = filter(lambda x: x.betaValue == max([v.betaValue for v in filter(lambda x: x.betaValue <= selectedBeta, at.attValues)]) ,at.attValues)[0]
nearestRight = filter(lambda x: x.betaValue == min([v.betaValue for v in filter(lambda x: x.betaValue >= selectedBeta, at.attValues)]) ,at.attValues)[0]
return (nearestLeft, nearestRight)
sum = self.nomogram.constant.betaValue
for at in self.nomogram.attributes:
sum += at.selectedValue[2]
variance = math.pow(self.nomogram.constant.error,2)
for at in self.nomogram.attributes:
# if not isinstance(at, AttrLineCont):
if at.selectedValue[2] == 0.0 and self.parent.alignType == 1:
continue
(nleft, nright) = getNearestAtt(at.selectedValue[2], at)
if nright.betaValue>nleft.betaValue:
prop = (at.selectedValue[2]-nleft.betaValue)/(nright.betaValue-nleft.betaValue)
else:
prop = 0
if prop == 0:
variance += math.pow(nleft.error, 2)
elif prop == 1:
variance += math.pow(nright.error, 2)
else:
variance += math.pow(nleft.error, 2)*(1-prop)
variance += math.pow(nright.error, 2)*prop
standard_error = math.sqrt(variance)
ax=self.m.mapBeta(sum, self.footer)
# get CI
ax_maxError = self.m.mapBeta(sum+standard_error*norm_factor(1-((1-float(self.parent.confidence_percent)/100.)/2.)), self.footer)
ax_minError = self.m.mapBeta(sum-standard_error*norm_factor(1-((1-float(self.parent.confidence_percent)/100.)/2.)), self.footer)
a = QPointArray()
a.makeArc(ax_minError, self.footer.marker.y()+10, 10, 10, 0, 180*16)
self.leftArc.setPoints(a)
#self.leftArc.setBrush(QBrush(Qt.blue))
a = QPointArray()
a.makeArc(ax_maxError-10, self.footer.marker.y()-5, 10, 10, 90*16, -90*16)
self.rightArc.setPoints(a)
a.makeArc(ax_minError, self.footerPercent.marker.y()-5, 10, 10, 90*16, 180*16)
self.leftPercentArc.setPoints(a)
a.makeArc(ax_maxError-10, self.footerPercent.marker.y()-5, 10, 10, 90*16, -90*16)
self.rightPercentArc.setPoints(a)
axPercentMin=self.m.mapBeta(self.footerPercent.minValue, self.footer)
axPercentMax=self.m.mapBeta(self.footerPercent.maxValue, self.footer)
axMin=self.m.mapBeta(self.footer.minValue, self.footer)
axMax=self.m.mapBeta(self.footer.maxValue, self.footer)
ax = max(ax, axMin)
ax = min(ax, axMax)
self.errorLine.setPoints(ax_minError, self.footer.marker.y(), ax_maxError, self.footer.marker.y())
self.errorLine.setCanvas(self)
ax_minError = min(ax_minError, axPercentMax)
ax_minError = max(ax_minError, axPercentMin)
ax_maxError = min(ax_maxError, axPercentMax)
ax_maxError = max(ax_maxError, axPercentMin)
self.errorPercentLine.setCanvas(self)
self.errorPercentLine.setPoints(ax_minError, self.footerPercent.marker.y(), ax_maxError, self.footerPercent.marker.y())
self.footer.selectedValue = [ax,self.footer.marker.y(),self.m.mapBetaToLinear(sum, self.footer)]
self.footer.marker.setPos(ax, self.footer.marker.y())
if ax>axPercentMax:
ax=axPercentMax
if ax<axPercentMin:
ax=axPercentMin
self.footerPercent.selectedValue = [ax,self.footer.marker.y(),1/(1+math.exp(-sum))]
self.footerPercent.marker.setPos(ax, self.footerPercent.marker.y())
if self.parent.probability:
self.footer.marker.show()
self.footerPercent.marker.show()
if self.footer.marker.x() == self.footerPercent.marker.x():
self.connectedLine.setPoints(self.footer.marker.x(), self.footer.marker.y(), self.footerPercent.marker.x(), self.footerPercent.marker.y())
self.connectedLine.setCanvas(self)
self.connectedLine.show()
else:
self.connectedLine.hide()
if self.parent.confidence_check:
self.showCI()
else:
self.hideCI()
self.update()
def showCI(self):
self.errorLine.show()
self.errorPercentLine.show()
def hideCI(self):
self.errorLine.hide()
self.errorPercentLine.hide()
self.leftArc.hide()
self.rightArc.hide()
self.leftPercentArc.hide()
self.rightPercentArc.hide()
# ####################################################################
# Main CANVAS
# ####################################################################
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -