def handleDrag(self, delta): if self.draggedHandle == None: return 0 original = self.draggedStart + self.draggedDistance projected = original + delta if self.draggedAxisIsX: if self.draggedBoundIsLow: if delta < 0: projected = max(projected,self.scatterBounds[0]) else: projected = min(projected,self.draggedHandle.parent.rightHandle.left(),self.scatterBounds[2]) else: if delta < 0: projected = max(projected,self.draggedHandle.parent.leftHandle.right(),self.scatterBounds[0]) else: projected = min(projected,self.scatterBounds[2]) else: if self.draggedBoundIsLow: if delta < 0: projected = max(projected,self.draggedHandle.parent.topHandle.bottom(),self.scatterBounds[1]) else: projected = min(projected,self.scatterBounds[3]) else: if delta < 0: projected = max(projected,self.scatterBounds[1]) else: projected = min(projected,self.draggedHandle.parent.bottomHandle.top(),self.scatterBounds[3]) delta = projected - original self.draggedDistance = projected - self.draggedStart if self.draggedAxisIsX: self.draggedHandle.label.setText(fitInSevenChars(self.screenToDataSpace(projected, self.scatterBounds[0], self.currentXaxis.minimum, self.xAxisRatio))) else: self.draggedHandle.label.setText(fitInSevenChars(self.screenToDataSpace(projected, self.scatterBounds[3], self.currentYaxis.minimum, self.yAxisRatio))) return delta
def notifyAxisChange(self, applyImmediately=True): # x axis att = self.app.currentXattribute self.currentXaxis = self.vData.axisLookups[att] low = self.currentXaxis.minimum high = self.currentXaxis.maximum ax = self.svgLayer.svg.xAxis right = self.scatterBounds[2] left = self.scatterBounds[0] ax.label.setText(att) ax.lowLabel.setText(fitInSevenChars(low)) ax.highLabel.setText(fitInSevenChars(high)) self.xAxisRatio = float(high - low) / float(right - left) if self.xAxisRatio == 0: self.xAxisRatio = 1.0 / float(right-left) if low <= 0 and high >= 0: self.svgLayer.svg.xZeroBar.show() self.svgLayer.svg.xZeroBar.moveTo(self.dataToScreenSpace(0.0, left, low, self.xAxisRatio)-self.svgLayer.svg.xZeroBar.width()/2,self.svgLayer.svg.xZeroBar.top()) else: self.svgLayer.svg.xZeroBar.hide() # y axis att = self.app.currentYattribute self.currentYaxis = self.vData.axisLookups[att] low = self.currentYaxis.minimum high = self.currentYaxis.maximum ax = self.svgLayer.svg.yAxis bottom = self.scatterBounds[3] top = self.scatterBounds[1] ax.label.setText(att) ax.lowLabel.setText(fitInSevenChars(low)) ax.highLabel.setText(fitInSevenChars(high)) self.yAxisRatio = float(high - low) / float(top-bottom) if self.yAxisRatio == 0: self.yAxisRatio = 1.0 / float(top-bottom) if low <= 0 and high >= 0: self.svgLayer.svg.yZeroBar.show() self.svgLayer.svg.yZeroBar.moveTo(self.svgLayer.svg.yZeroBar.left(),self.dataToScreenSpace(0.0, bottom, low, self.yAxisRatio)-self.svgLayer.svg.yZeroBar.height()/2) else: self.svgLayer.svg.yZeroBar.hide() if applyImmediately: self.notifySelection(self.app.intMan.activePoints, self.app.intMan.activeParams) self.allDataLayer.setup() self.selectedLayer.updateAxes() self.highlightedLayer.updateAxes()
def updateNumeric(self, ranges): if self.dataAxis.hasNumeric: while len(self.numericRanges) > len(ranges): self.numericRanges[-1].delete() del self.numericRanges[-1] while len(ranges) > len(self.numericRanges): self.numericRanges.append(self.numericRanges[-1].clone()) for i,(low,high) in enumerate(ranges): v = self.numericRanges[i] # are parts (or all) of the selection hidden? topPixel = self.dataToScreen(high)[0] bottomPixel = self.dataToScreen(low)[0] if topPixel < self.numericPixelHigh or topPixel - v.topHandle.height() > self.numericPixelLow: v.topHandle.hide() else: v.topHandle.label.setText(fitInSevenChars(high)) v.topHandle.moveTo(v.topHandle.left(),topPixel-v.topHandle.height()) v.topHandle.show() topPixel = max(topPixel,self.numericPixelHigh) topPixel = min(topPixel,self.numericPixelLow) if bottomPixel > self.numericPixelLow+1 or bottomPixel + v.bottomHandle.height() < self.numericPixelHigh: v.bottomHandle.hide() else: v.bottomHandle.label.setText(fitInSevenChars(low)) v.bottomHandle.moveTo(v.bottomHandle.left(),bottomPixel) v.bottomHandle.show() bottomPixel = min(self.numericPixelLow,bottomPixel) bottomPixel = max(self.numericPixelHigh,bottomPixel) if bottomPixel >= topPixel: v.bar.setSize(v.bar.width(),1) v.bar.moveTo(v.bar.left(),topPixel) v.bar.setSize(v.bar.width(),bottomPixel-topPixel) v.bar.show()
def handleDrag(self, element, delta): if self.draggedHandle == None: self.startDrag(element) original = self.draggedStart + self.draggedDistance projected = original + delta if self.draggedBoundIsLow: if delta < 0: projected = max(projected,self.draggedHandle.parent.topHandle.bottom(),self.numericPixelHigh) else: projected = min(projected,self.numericPixelLow) else: if delta < 0: projected = max(projected,self.numericPixelHigh) else: projected = min(projected,self.draggedHandle.parent.bottomHandle.top(),self.numericPixelLow) delta = projected - original self.draggedDistance = projected - self.draggedStart self.draggedHandle.label.setText(fitInSevenChars(self.screenToData(projected))) return delta
def __init__(self, name, vData, visAxis, visible, parent): self.name = name self.vData = vData self.dataAxis = vData.axisLookups[self.name] self.visAxis = visAxis self.visible = visible self.parent = parent # handle # this is an ugly hack to get around SVG (and QtSvg)'s issues with text m = self.name.rfind('(') if m == -1: filename = "" attName = " ".join(self.name.split()) else: filename = self.name[m:].strip() attName = " ".join(self.name[:m].strip().split()) row1 = attName[:15] row2 = attName[15:] if len(row2) > 15: row2 = "..." + row2[-12:] row3 = filename if len(row3) > 15: row3 = row3[:12] + "..." self.visAxis.handle.label1.setText(row1) self.visAxis.handle.label2.setText(row2) self.visAxis.handle.label3.setText(row3) # numeric self.dataToPixelRatio = 1.0 self.pixelToDataRatio = 1.0 self.numericDataLow = self.dataAxis.minimum self.numericDataHigh = self.dataAxis.maximum self.numericPixelLow = self.visAxis.numeric.scrollDownBar.top() self.numericPixelHigh = self.visAxis.numeric.scrollUpBar.bottom() self.numericRanges = [] if not self.dataAxis.hasNumeric: #TODO: hide/show numeric area via context menu.... self.visAxis.numeric.delete() self.visAxis.categorical.scrollUpBar.translate(0,self.visAxis.spacer.top()-self.visAxis.categorical.scrollUpBar.top()) else: if self.numericDataLow == self.numericDataHigh: # don't allow a numeric range of zero self.numericDataHigh += 1 self.pixelToDataRatio = float(self.numericDataHigh-self.numericDataLow)/float(self.numericPixelHigh-self.numericPixelLow) self.dataToPixelRatio = 1.0/self.pixelToDataRatio self.visAxis.numeric.scrollUpBar.label.setText(fitInSevenChars(self.dataAxis.maximum)) self.visAxis.numeric.scrollDownBar.label.setText(fitInSevenChars(self.dataAxis.minimum)) self.numericRanges.append(self.visAxis.numeric.selectionGroup.selectionRange) self.draggedHandle = None self.draggedBoundIsLow = None self.draggedDistance = None self.draggedStart = None # categorical self.rootCatNode = None self.tailCatNode = None self.catLattice = {-1:set()} # lattice number to labelHandler; -1 and 1 more than the number of possible spaces are for offscreen, hidden nodes self.cats = {} # label to lattice number self.visPool = {'Allele Masked':None,'Missing':None,'Text Items':[]} # figure out some globals self.labelTop = self.visAxis.categorical.scrollUpBar.bottom() self.labelBottom = self.visAxis.categorical.scrollDownBar.top() self.itemHeight = self.visAxis.categorical.itemGroup.alleleMasked.height() # allele masked is the tallest one # sort the items by set membership size, except put Allele Masked, Missing last. Also populate the visPool with the right number of elements temp = [] for label in self.dataAxis.categoricalKeys: if label == 'Allele Masked' or label == 'Missing': continue temp.append((self.dataAxis.lookup.count(label),label)) poolItem = self.visAxis.categorical.itemGroup.textItem.clone() self.visPool['Text Items'].append(poolItem) temp = sorted(temp) self.visAxis.categorical.itemGroup.textItem.delete() numMasked = self.dataAxis.lookup.count('Allele Masked') if numMasked > 0: temp.append((numMasked,'Allele Masked')) self.visPool['Allele Masked'] = self.visAxis.categorical.itemGroup.alleleMasked else: self.visAxis.categorical.itemGroup.alleleMasked.delete() numMissing = self.dataAxis.lookup.count('Missing') if numMissing > 0: temp.append((numMissing,'Missing')) self.visPool['Missing'] = self.visAxis.categorical.itemGroup.missing else: self.visAxis.categorical.itemGroup.missing.delete() # Figure out some more globals now that we know how many/which items we have self.numVisibleCats = len(temp) self.allCatsVisible = self.maximizeLatticeSpace() # create nodes from the end of the list to the beginning - we know the bottom scroll arrow will start hidden self.visAxis.categorical.scrollDownBar.hide() if self.allCatsVisible: self.visAxis.categorical.scrollUpBar.hide() self.catLattice[self.latticeLength] = set() latticeNumber = self.latticeLength-1 if self.numVisibleCats == 0: self.rootCatNode = None else: self.rootCatNode = labelHandler(temp[-1][1], latticeNumber) self.cats[temp[-1][1]] = latticeNumber self.assignVisElement(self.rootCatNode, None) lastNode = self.rootCatNode latticeNumber -= 1 for size,label in reversed(temp[:-1]): newNode = labelHandler(label,latticeNumber) self.cats[label] = latticeNumber if latticeNumber > -1: self.assignVisElement(newNode, lastNode) self.catLattice[latticeNumber] = newNode latticeNumber -= 1 if latticeNumber == 0: self.tailCatNode = newNode else: self.catLattice[-1].add(newNode) lastNode.p = newNode newNode.n = lastNode lastNode = newNode # hide everything that's unused in the visPool for v in self.visPool['Text Items']: v.hide()
def notifySelection(self, activePoints, activeParams): self.selectedLayer.update(activePoints) self.selectedLayer.setDirty() # pull out the sizes of things once before we manipulate everything - this should help minimize re-rendering xAtt = self.app.currentXattribute numericLeftPixel = self.scatterBounds[0] numericRightPixel = self.scatterBounds[2] rightHandleSize = self.xRanges[0].rightHandle.width() rightHandleTop = self.xRanges[0].rightHandle.top() leftHandleSize = self.xRanges[0].leftHandle.width() leftHandleTop = self.xRanges[0].leftHandle.top() xBarSize = self.xRanges[0].bar.height() xBarTop = self.xRanges[0].bar.top() yAtt = self.app.currentYattribute numericBottomPixel = self.scatterBounds[3] numericTopPixel = self.scatterBounds[1] topHandleSize = self.yRanges[0].topHandle.height() topHandleLeft = self.yRanges[0].topHandle.left() bottomHandleSize = self.yRanges[0].bottomHandle.height() bottomHandleLeft = self.yRanges[0].bottomHandle.left() yBarSize = self.yRanges[0].bar.width() yBarLeft = self.yRanges[0].bar.left() # remove, duplicate the number of svg selection groups to fit the data # x axis i = len(self.xRanges) - 1 while len(self.xRanges) > len(activeParams[xAtt][0]): self.xRanges[i].delete() del self.xRanges[i] i -= 1 while len(self.xRanges) < len(activeParams[xAtt][0]): self.xRanges.append(self.xRanges[0].clone()) # y axis i = len(self.yRanges) - 1 while len(self.yRanges) > len(activeParams[yAtt][0]): self.yRanges[i].delete() del self.yRanges[i] i -= 1 while len(self.yRanges) < len(activeParams[yAtt][0]): self.yRanges.append(self.yRanges[0].clone()) # adjust each selection group to the data # x axis for i,r in enumerate(activeParams[xAtt][0]): l = r[0] h = r[1] v = self.xRanges[i] # are parts (or all) of the selection hidden? rightPixel = numericRightPixel - float(self.currentXaxis.maximum-h)/self.xAxisRatio leftPixel = numericLeftPixel + float(l-self.currentXaxis.minimum)/self.xAxisRatio if rightPixel + rightHandleSize < numericLeftPixel or rightPixel > numericRightPixel: v.rightHandle.hide() else: v.rightHandle.label.setText(fitInSevenChars(h)) v.rightHandle.moveTo(rightPixel,rightHandleTop) v.rightHandle.show() rightPixel = max(rightPixel,numericLeftPixel) rightPixel = min(rightPixel,numericRightPixel) if leftPixel < numericLeftPixel or leftPixel - leftHandleSize > numericRightPixel: v.leftHandle.hide() else: v.leftHandle.label.setText(fitInSevenChars(l)) v.leftHandle.moveTo(leftPixel - leftHandleSize, leftHandleTop) v.leftHandle.show() leftPixel = min(numericRightPixel,leftPixel) leftPixel = max(numericLeftPixel,leftPixel) if leftPixel >= rightPixel: v.bar.setSize(1,xBarSize) v.bar.moveTo(leftPixel,xBarTop) v.bar.setSize(rightPixel-leftPixel,xBarSize) v.bar.show() # y axis for i,r in enumerate(activeParams[yAtt][0]): l = r[0] h = r[1] v = self.yRanges[i] # are parts (or all) of the selection hidden? topPixel = self.dataToScreenSpace(h, self.scatterBounds[3], self.currentYaxis.minimum, self.yAxisRatio) bottomPixel = self.dataToScreenSpace(l, self.scatterBounds[3], self.currentYaxis.minimum, self.yAxisRatio) if topPixel - topHandleSize > numericBottomPixel or topPixel < numericTopPixel: v.topHandle.hide() else: v.topHandle.label.setText(fitInSevenChars(h)) v.topHandle.moveTo(topHandleLeft,topPixel - topHandleSize) v.topHandle.show() topPixel = max(topPixel,numericTopPixel) topPixel = min(topPixel,numericBottomPixel) if bottomPixel > numericBottomPixel or bottomPixel + bottomHandleSize < numericTopPixel: v.bottomHandle.hide() else: v.bottomHandle.label.setText(fitInSevenChars(l)) v.bottomHandle.moveTo(bottomHandleLeft,bottomPixel) v.bottomHandle.show() bottomPixel = min(bottomPixel,numericBottomPixel) bottomPixel = max(bottomPixel,numericTopPixel) if topPixel >= bottomPixel: v.bar.setSize(yBarSize,1) v.bar.moveTo(yBarLeft,topPixel) v.bar.setSize(yBarSize,bottomPixel-topPixel) v.bar.show()