📄 owmosaicdisplay.py
字号:
# draw rectangles
self.DrawData(attrList, (xOff, xOff+squareSize), (yOff, yOff+squareSize), 0, "", len(attrList))
self.DrawLegend(data, (xOff, xOff+squareSize), (yOff, yOff+squareSize)) # draw class legend
self.canvas.update()
# ############################################################################
# ############################################################################
## DRAW DATA - draw rectangles for attributes in attrList inside rect (x0,x1), (y0,y1)
def DrawData(self, attrList, (x0, x1), (y0, y1), side, condition, totalAttrs, lastValueForFirstAttribute = 0, usedAttrs = [], usedVals = [], attrVals = ""):
if self.conditionalDict[attrVals] == 0:
self.addRect(x0, x1, y0, y1, attrVals = attrVals)
self.DrawText(side, attrList[0], (x0, x1), (y0, y1), totalAttrs, lastValueForFirstAttribute, attrVals) # store coordinates for later drawing of labels
return
attr = attrList[0]
edge = len(attrList) * self.cellspace # how much smaller rectangles do we draw
values = self.attributeValuesDict.get(attr, None) or getVariableValuesSorted(self.data, attr)
if side%2: values = values[::-1] # reverse names if necessary
if side%2 == 0: # we are drawing on the x axis
whole = max(0, (x1-x0)-edge*(len(values)-1)) # we remove the space needed for separating different attr. values
if whole == 0: edge = (x1-x0)/float(len(values)-1)
else: # we are drawing on the y axis
whole = max(0, (y1-y0)-edge*(len(values)-1))
if whole == 0: edge = (y1-y0)/float(len(values)-1)
currPos = 0.0
if attrVals == "": counts = [self.conditionalDict[val] for val in values]
else: counts = [self.conditionalDict[attrVals + "-" + val] for val in values]
total = sum(counts)
for i in range(len(counts)):
val = values[i]
size = whole*float(counts[i])/float(total)
htmlVal = getHtmlCompatibleString(val)
if attrVals != "": newAttrVals = attrVals + "-" + val
else: newAttrVals = val
if side % 2 == 0: # if drawing horizontal
if len(attrList) == 1: self.addRect(x0+currPos, x0+currPos+size, y0, y1, condition + 4*" " + attr + ": <b>" + htmlVal + "</b><br>", usedAttrs + [attr], usedVals + [val], newAttrVals)
else: self.DrawData(attrList[1:], (x0+currPos, x0+currPos+size), (y0, y1), side +1, condition + 4*" " + attr + ": <b>" + htmlVal + "</b><br>", totalAttrs, lastValueForFirstAttribute + int(val == values[-1]), usedAttrs + [attr], usedVals + [val], newAttrVals)
else:
if len(attrList) == 1: self.addRect(x0, x1, y0+currPos, y0+currPos+size, condition + 4*" " + attr + ": <b> " + htmlVal + "</b><br>", usedAttrs + [attr], usedVals + [val], newAttrVals)
else: self.DrawData(attrList[1:], (x0, x1), (y0+currPos, y0+currPos+size), side +1, condition + 4*" " + attr + ": <b>" + htmlVal + "</b><br>", totalAttrs, lastValueForFirstAttribute, usedAttrs + [attr], usedVals + [val], newAttrVals)
currPos += size + edge
self.DrawText(side, attrList[0], (x0, x1), (y0, y1), totalAttrs, lastValueForFirstAttribute, attrVals)
######################################################################
## DRAW TEXT - draw legend for all attributes in attrList and their possible values
def DrawText(self, side, attr, (x0, x1), (y0, y1), totalAttrs, lastValueForFirstAttribute, attrVals):
if self.drawnSides[side]: return
#if side == RIGHT and lastValueForFirstAttribute != 2: return
if side == RIGHT:
if lastValueForFirstAttribute != 2: return
elif not self.conditionalDict[attrVals]:
self.conditionalDict[attrVals] = [1 for i in range(len(getVariableValuesSorted(self.data, attr)))]
if not self.conditionalDict[attrVals]:
if not self.drawPositions.has_key(side): self.drawPositions[side] = (x0, x1, y0, y1)
return
else:
if self.drawPositions.has_key(side): (x0, x1, y0, y1) = self.drawPositions[side] # restore the positions where we have to draw the attribute values and attribute name
self.drawnSides[side] = 1
values = self.attributeValuesDict.get(attr, None) or getVariableValuesSorted(self.data, attr)
if side % 2: values = values[::-1]
width = x1-x0 - (side % 2 == 0) * self.cellspace*(totalAttrs-side)*(len(values)-1)
height = y1-y0 - (side % 2 == 1) * self.cellspace*(totalAttrs-side)*(len(values)-1)
#calculate position of first attribute
if side == 0: OWCanvasText(self.canvas, attr, x0+(x1-x0)/2, y1 + self.attributeNameOffset, Qt.AlignCenter, bold = 1)
elif side == 1: OWCanvasText(self.canvas, attr, x0 - self.attributeNameOffset, y0+(y1-y0)/2, Qt.AlignRight + Qt.AlignVCenter, bold = 1)
elif side == 2: OWCanvasText(self.canvas, attr, x0+(x1-x0)/2, y0 - self.attributeNameOffset, Qt.AlignCenter, bold = 1)
else: OWCanvasText(self.canvas, attr, x1 + self.attributeNameOffset, y0+(y1-y0)/2, Qt.AlignLeft + Qt.AlignVCenter, bold = 1)
currPos = 0
if attrVals == "": counts = [self.conditionalDict.get(val, 1) for val in values]
else: counts = [self.conditionalDict.get(attrVals + "-" + val, 1) for val in values]
total = sum(counts)
if total == 0:
counts = [1]*len(values)
total = sum(counts)
for i in range(len(values)):
val = values[i]
perc = counts[i]/float(total)
if side == 0: OWCanvasText(self.canvas, str(val), x0+currPos+width*0.5*perc, y1 + self.attributeValueOffset, Qt.AlignCenter, bold = 0)
elif side == 1: OWCanvasText(self.canvas, str(val), x0-self.attributeValueOffset, y0+currPos+height*0.5*perc, Qt.AlignRight + Qt.AlignVCenter, bold = 0)
elif side == 2: OWCanvasText(self.canvas, str(val), x0+currPos+width*perc*0.5, y0 - self.attributeValueOffset, Qt.AlignCenter, bold = 0)
else: OWCanvasText(self.canvas, str(val), x1+self.attributeValueOffset, y0 + currPos + height*0.5*perc, Qt.AlignLeft + Qt.AlignVCenter, bold = 0)
if side % 2 == 0: currPos += perc*width + self.cellspace*(totalAttrs-side)
else : currPos += perc*height+ self.cellspace*(totalAttrs-side)
# draw the class legend below the square
def DrawLegend(self, data, (x0, x1), (y0, y1)):
if self.interiorColoring == CLASS_DISTRIBUTION and (not data.domain.classVar or data.domain.classVar.varType == orange.VarTypes.Continuous): return
if self.interiorColoring == PEARSON:
names = ["<-8", "-8:-4", "-4:-2", "-2:2", "2:4", "4:8", ">8", "Residuals:"]
colors = self.redColors[::-1] + self.blueColors[1:]
else:
names = (self.attributeValuesDict.get(data.domain.classVar.name, None) or getVariableValuesSorted(data, data.domain.classVar.name)) + [data.domain.classVar.name+":"]
colors = [self.colorPalette[i] for i in range(len(data.domain.classVar.values))]
for name in names:
self.names.append(OWCanvasText(self.canvas, name))
totalWidth = sum([self.names[i].boundingRect().width() for i in range(len(self.names))])
# compute the x position of the center of the legend
y = y1 + self.attributeNameOffset + 20
distance = 30
startX = (x0+x1)/2 - (totalWidth + (len(names))*distance)/2
self.names[-1].move(startX+15, y+1); self.names[-1].show()
xOffset = self.names[-1].boundingRect().width() + distance
size = 16 # 8 + 8*(self.interiorColoring == PEARSON)
for i in range(len(names)-1):
if self.interiorColoring == PEARSON: edgeColor = Qt.black
else: edgeColor = colors[i]
OWCanvasRectangle(self.canvas, startX + xOffset, y-size/2, size, size, edgeColor, colors[i])
self.names[i].move(startX + xOffset + 18, y)
xOffset += distance + self.names[i].boundingRect().width()
# draw a rectangle, set it to back and add it to rect list
def addRect(self, x0, x1, y0, y1, condition = "", usedAttrs = [], usedVals = [], attrVals = ""):
x0 = int(x0); x1 = int(x1); y0 = int(y0); y1 = int(y1)
if x0 == x1: x1+=1
if y0 == y1: y1+=1
if x1-x0 + y1-y0 == 2: y1+=1 # if we want to show a rectangle of width and height 1 it doesn't show anything. in such cases we therefore have to increase size of one edge
rect = OWCanvasRectangle(self.canvas, x0, y0, x1-x0, y1-y0, z = 30)
# we have to remember which conditions were new in this update so that when we right click we can only remove the last added selections
if self.selectionRectangle != None and rect in self.canvas.collisions(self.selectionRectangle) and not self.selectionConditionsDict.has_key((tuple(usedAttrs), tuple(usedVals))):
self.recentlyAdded = getattr(self, "recentlyAdded", []) + [(tuple(usedAttrs), tuple(usedVals))]
self.selectionConditionsDict[(tuple(usedAttrs), tuple(usedVals))] = 1
# show rectangle selected or not
if self.selectionConditionsDict.has_key((tuple(usedAttrs), tuple(usedVals))):
rect.setPen(QPen(Qt.black, 3, Qt.DotLine))
if self.updateSelectedData:
pp = orange.Preprocessor_take()
for i in range(len(usedAttrs)):
pp.values[self.data.domain[usedAttrs[i]]] = usedVals[i]
tempData = pp(self.data)
if not self.selectedData: self.selectedData = tempData
else: self.selectedData.extend(tempData)
# if we have selected a rule that contains this combination of attr values then show a kind of selection of this rectangle
if self.activeRule and len(usedAttrs) == len(self.activeRule[0]) and sum([v in usedAttrs for v in self.activeRule[0]]) == len(self.activeRule[0]):
for vals in self.activeRule[1]:
if usedVals == [vals[self.activeRule[0].index(a)] for a in usedAttrs]:
values = self.attributeValuesDict.get(self.data.domain.classVar.name, None) or getVariableValuesSorted(self.data, self.data.domain.classVar.name)
counts = [self.conditionalDict[attrVals + "-" + val] for val in values]
d = 2
r = OWCanvasRectangle(self.canvas, x0-d, y0-d, x1-x0+2*d+1, y1-y0+2*d+1, z = 50)
r.setPen(QPen(self.colorPalette[counts.index(max(counts))], 2, Qt.DashLine))
if not self.conditionalDict[attrVals]: return rect
if self.interiorColoring == CLASS_DISTRIBUTION and (not self.data.domain.classVar or not self.data.domain.classVar.varType == orange.VarTypes.Discrete):
return rect
aprioriDist = None; pearson = None; expected = None
# draw pearsons residuals
if self.interiorColoring == PEARSON or not self.data.domain.classVar or self.data.domain.classVar.varType != orange.VarTypes.Discrete:
s = sum(self.aprioriDistributions[0])
expected = s * reduce(lambda x, y: x*y, [self.aprioriDistributions[i][usedVals[i]]/float(s) for i in range(len(usedVals))])
actual = self.conditionalDict[attrVals]
pearson = float(actual - expected) / sqrt(expected)
if abs(pearson) < 2: ind = 0
elif abs(pearson) < 4: ind = 1
elif abs(pearson) < 8: ind = 2
else: ind = 3
if pearson > 0: color = self.blueColors[ind]
else: color = self.redColors[ind]
rect = OWCanvasRectangle(self.canvas, x0, y0, x1-x0, y1-y0, color, color, z = -20)
# draw class distribution - actual and apriori
else:
clsValues = self.attributeValuesDict.get(self.data.domain.classVar.name, None) or getVariableValuesSorted(self.data, self.data.domain.classVar.name)
aprioriDist = orange.Distribution(self.data.domain.classVar.name, self.data)
total = 0
for i in range(len(clsValues)):
val = self.conditionalDict[attrVals + "-" + clsValues[i]]
if self.horizontalDistribution:
if i == len(clsValues)-1: v = x1-x0 - total
else: v = int(((x1-x0)* val)/self.conditionalDict[attrVals])
OWCanvasRectangle(self.canvas, x0+total, y0, v, y1-y0, self.colorPalette[i], self.colorPalette[i], z = -20)
else:
if i == len(clsValues)-1: v = y1-y0 - total
else: v = int(((y1-y0)* val)/self.conditionalDict[attrVals])
OWCanvasRectangle(self.canvas, x0, y0+total, x1-x0, v, self.colorPalette[i], self.colorPalette[i], z = -20)
total += v
# show apriori boxes and lines
if (self.showAprioriDistributionLines or self.useBoxes) and abs(x1 - x0) > self.boxSize and abs(y1 - y0) > self.boxSize:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -