Esempio n. 1
0
class OWSieveDiagram(OWWidget):
    name = "Sieve Diagram"
    icon = "icons/SieveDiagram.svg"
    priority = 4200

    inputs = [("Data", Table, "setData", Default),
              ("Features", AttributeList, "setShownAttributes")]
    outputs = []

    settingsList = ["showLines", "showCases", "showInColor"]

    def __init__(self, parent=None, signalManager=None):
        OWWidget.__init__(self, parent, signalManager, "Sieve diagram", True)

        #self.controlArea.setMinimumWidth(250)

        #set default settings
        self.data = None

        self.attrX = ""
        self.attrY = ""
        self.attrCondition = ""
        self.attrConditionValue = ""
        self.showLines = 1
        self.showCases = 0
        self.showInColor = 1
        self.attributeSelectionList = None
        self.stopCalculating = 0

        self.canvas = QGraphicsScene()
        self.canvasView = QGraphicsView(self.canvas, self.mainArea)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        #GUI
        self.attrSelGroup = gui.widgetBox(self.controlArea,
                                          box="Shown attributes")

        self.attrXCombo = gui.comboBox(
            self.attrSelGroup,
            self,
            value="attrX",
            label="X attribute:",
            orientation="horizontal",
            tooltip="Select an attribute to be shown on the X axis",
            callback=self.updateGraph,
            sendSelectedValue=1,
            valueType=str,
            labelWidth=70)
        self.attrYCombo = gui.comboBox(
            self.attrSelGroup,
            self,
            value="attrY",
            label="Y attribute:",
            orientation="horizontal",
            tooltip="Select an attribute to be shown on the Y axis",
            callback=self.updateGraph,
            sendSelectedValue=1,
            valueType=str,
            labelWidth=70)

        gui.separator(self.controlArea)

        self.conditionGroup = gui.widgetBox(self.controlArea, box="Condition")
        self.attrConditionCombo = gui.comboBox(
            self.conditionGroup,
            self,
            value="attrCondition",
            label="Attribute:",
            orientation="horizontal",
            callback=self.updateConditionAttr,
            sendSelectedValue=1,
            valueType=str,
            labelWidth=70)
        self.attrConditionValueCombo = gui.comboBox(self.conditionGroup,
                                                    self,
                                                    value="attrConditionValue",
                                                    label="Value:",
                                                    orientation="horizontal",
                                                    callback=self.updateGraph,
                                                    sendSelectedValue=1,
                                                    valueType=str,
                                                    labelWidth=70)

        gui.separator(self.controlArea)

        box2 = gui.widgetBox(self.controlArea, box="Visual settings")
        gui.checkBox(box2,
                     self,
                     "showLines",
                     "Show lines",
                     callback=self.updateGraph)
        hbox = gui.widgetBox(box2, orientation="horizontal")
        gui.checkBox(hbox,
                     self,
                     "showCases",
                     "Show data examples...",
                     callback=self.updateGraph)
        gui.checkBox(hbox,
                     self,
                     "showInColor",
                     "...in color",
                     callback=self.updateGraph)

        gui.separator(self.controlArea)
        # self.optimizationDlg = OWSieveOptimization(self, self.signalManager)
        # optimizationButtons = gui.widgetBox(self.controlArea, "Dialogs", orientation = "horizontal")
        # gui.button(optimizationButtons, self, "VizRank", callback = self.optimizationDlg.reshow, debuggingEnabled = 0, tooltip = "Find attribute groups with highest value dependency")

        gui.rubber(self.controlArea)

        # self.wdChildDialogs = [self.optimizationDlg]        # used when running widget debugging
        # self.graphButton.clicked.connect(self.saveToFileCanvas)
        self.icons = gui.attributeIconDict
        self.resize(800, 550)
        random.seed()

    def sendReport(self):
        self.startReport("%s [%s, %s]" %
                         (self.windowTitle(), self.attrX, self.attrY))
        self.reportSettings(
            "",
            [("X-Attribute", self.attrX),
             ("Y-Attribute", self.attrY), self.attrCondition != "(None)" and
             ("Condition", "%s = '%s'" %
              (self.attrCondition, self.attrConditionValue))])
        # self.reportImage(lambda *x: OWChooseImageSizeDlg(self.canvas).saveImage(*x))

    # receive new data and update all fields
    def setData(self, data):
        if type(data) == SqlTable and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.information(0)
        self.information(1)
        sameDomain = self.data and data and self.data.domain.checksum(
        ) == data.domain.checksum(
        )  # preserve attribute choice if the domain is the same
        # self.data = self.optimizationDlg.setData(data, 0)
        self.data = data

        self.warning(0, "")
        if data:
            if any(
                    isinstance(attr, ContinuousVariable)
                    for attr in data.domain):
                self.warning(
                    0, "Data contains continuous variables. " +
                    "Discretize the data to use them.")

        if not sameDomain:
            self.initCombos()

        self.setShownAttributes(self.attributeSelectionList)

    ## Attribute selection signal
    def setShownAttributes(self, attrList):
        self.attributeSelectionList = attrList
        if self.data and self.attributeSelectionList and len(attrList) >= 2:
            attrs = [attr.name for attr in self.data.domain]
            if attrList[0] in attrs and attrList[1] in attrs:
                self.attrX = attrList[0]
                self.attrY = attrList[1]
        self.updateGraph()

    # create data subset depending on conditional attribute and value
    def getConditionalData(self, xAttr=None, yAttr=None, dropMissingData=1):
        if not self.data: return None

        if not xAttr: xAttr = self.attrX
        if not yAttr: yAttr = self.attrY
        if not (xAttr and yAttr): return

        if self.attrCondition == "(None)":
            data = self.data[:, [xAttr, yAttr]]
            # data = self.data.select([xAttr, yAttr])
        else:
            # data = orange.Preprocessor_dropMissing(self.data.select([xAttr, yAttr, self.attrCondition]))
            # data = self.data.select({self.attrCondition:self.attrConditionValue})
            fd = Orange.data.filter.FilterDiscrete(
                column=self.attrCondition, values=[self.attrConditionValue])
            filt = Orange.data.filter.Values([fd])
            filt.domain = self.data.domain
            data = filt(self.data)

        # if dropMissingData: return orange.Preprocessor_dropMissing(data)
        #else:
        return data

    # new conditional attribute was set - update graph
    def updateConditionAttr(self):
        self.attrConditionValueCombo.clear()

        if self.attrCondition != "(None)":
            for val in self.data.domain[self.attrCondition].values:
                self.attrConditionValueCombo.addItem(val)
            self.attrConditionValue = str(
                self.attrConditionValueCombo.itemText(0))
        self.updateGraph()

    # initialize lists for shown and hidden attributes
    def initCombos(self):
        self.attrXCombo.clear()
        self.attrYCombo.clear()
        self.attrConditionCombo.clear()
        self.attrConditionCombo.addItem("(None)")
        self.attrConditionValueCombo.clear()

        if not self.data: return
        for i, var in enumerate(self.data.domain):
            if isinstance(var, DiscreteVariable):
                self.attrXCombo.addItem(self.icons[self.data.domain[i]],
                                        self.data.domain[i].name)
                self.attrYCombo.addItem(self.icons[self.data.domain[i]],
                                        self.data.domain[i].name)
                self.attrConditionCombo.addItem(
                    self.icons[self.data.domain[i]], self.data.domain[i].name)
        self.attrCondition = str(self.attrConditionCombo.itemText(0))

        if self.attrXCombo.count() > 0:
            self.attrX = str(self.attrXCombo.itemText(0))
            self.attrY = str(
                self.attrYCombo.itemText(self.attrYCombo.count() > 1))

    def resizeEvent(self, e):
        OWWidget.resizeEvent(self, e)
        self.updateGraph()

    def showEvent(self, ev):
        OWWidget.showEvent(self, ev)
        self.updateGraph()

    ## updateGraph - gets called every time the graph has to be updated
    def updateGraph(self, *args):
        for item in self.canvas.items():
            self.canvas.removeItem(item)  # remove all canvas items
        if not self.data: return
        if not self.attrX or not self.attrY: return

        data = self.getConditionalData()
        if not data or len(data) == 0: return

        valsX = []
        valsY = []
        # contX = orange.ContingencyAttrAttr(self.attrX, self.attrX, data)   # distribution of X attribute
        # contY = orange.ContingencyAttrAttr(self.attrY, self.attrY, data)   # distribution of Y attribute
        contX = get_contingency(data, self.attrX, self.attrX)
        contY = get_contingency(data, self.attrY, self.attrY)

        # compute contingency of x and y attributes
        for entry in contX:
            sum_ = 0
            try:
                for val in entry:
                    sum_ += val
            except:
                pass
            valsX.append(sum_)

        for entry in contY:
            sum_ = 0
            try:
                for val in entry:
                    sum_ += val
            except:
                pass
            valsY.append(sum_)

        # create cartesian product of selected attributes and compute contingency
        # (cart, profit) = FeatureByCartesianProduct(data, [data.domain[self.attrX], data.domain[self.attrY]])
        # tempData = data.select(list(data.domain) + [cart])
        # contXY = orange.ContingencyAttrAttr(cart, cart, tempData)   # distribution of X attribute
        # contXY = get_contingency(tempData, cart, cart)
        contXY = self.getConditionalDistributions(
            data, [data.domain[self.attrX], data.domain[self.attrY]])

        # compute probabilities
        probs = {}
        for i in range(len(valsX)):
            valx = valsX[i]
            for j in range(len(valsY)):
                valy = valsY[j]

                actualProb = 0
                try:
                    actualProb = contXY['%s-%s' %
                                        (data.domain[self.attrX].values[i],
                                         data.domain[self.attrY].values[j])]
                    # for val in contXY['%s-%s' %(i, j)]: actualProb += val
                except:
                    actualProb = 0
                probs['%s-%s' % (data.domain[self.attrX].values[i],
                                 data.domain[self.attrY].values[j])] = ((
                                     data.domain[self.attrX].values[i],
                                     valx), (data.domain[self.attrY].values[j],
                                             valy), actualProb, len(data))

        # get text width of Y attribute name
        text = OWCanvasText(self.canvas,
                            data.domain[self.attrY].name,
                            x=0,
                            y=0,
                            bold=1,
                            show=0,
                            vertical=True)
        xOff = int(text.boundingRect().height() + 40)
        yOff = 50
        sqareSize = min(self.canvasView.width() - xOff - 35,
                        self.canvasView.height() - yOff - 30)
        if sqareSize < 0: return  # canvas is too small to draw rectangles
        self.canvasView.setSceneRect(0, 0, self.canvasView.width(),
                                     self.canvasView.height())

        # print graph name
        if self.attrCondition == "(None)":
            name = "<b>P(%s, %s) &#8800; P(%s)&times;P(%s)</b>" % (
                self.attrX, self.attrY, self.attrX, self.attrY)
        else:
            name = "<b>P(%s, %s | %s = %s) &#8800; P(%s | %s = %s)&times;P(%s | %s = %s)</b>" % (
                self.attrX, self.attrY, self.attrCondition,
                getHtmlCompatibleString(
                    self.attrConditionValue), self.attrX, self.attrCondition,
                getHtmlCompatibleString(
                    self.attrConditionValue), self.attrY, self.attrCondition,
                getHtmlCompatibleString(self.attrConditionValue))
        OWCanvasText(self.canvas,
                     "",
                     xOff + sqareSize / 2,
                     20,
                     Qt.AlignCenter,
                     htmlText=name)
        OWCanvasText(self.canvas,
                     "N = " + str(len(data)),
                     xOff + sqareSize / 2,
                     38,
                     Qt.AlignCenter,
                     bold=0)

        ######################
        # compute chi-square
        chisquare = 0.0
        for i in range(len(valsX)):
            for j in range(len(valsY)):
                ((xAttr, xVal), (yAttr, yVal), actual,
                 sum_) = probs['%s-%s' % (data.domain[self.attrX].values[i],
                                          data.domain[self.attrY].values[j])]
                expected = float(xVal * yVal) / float(sum_)
                if expected == 0: continue
                pearson2 = (actual - expected) * (actual - expected) / expected
                chisquare += pearson2

        ######################
        # draw rectangles
        currX = xOff
        max_ylabel_w = 0

        normX, normY = sum(valsX), sum(valsY)
        for i in range(len(valsX)):
            if valsX[i] == 0: continue
            currY = yOff
            width = int(float(sqareSize * valsX[i]) / float(normX))

            #for j in range(len(valsY)):
            for j in range(len(valsY) - 1, -1,
                           -1):  # this way we sort y values correctly
                ((xAttr, xVal), (yAttr, yVal), actual,
                 sum_) = probs['%s-%s' % (data.domain[self.attrX].values[i],
                                          data.domain[self.attrY].values[j])]
                if valsY[j] == 0: continue
                height = int(float(sqareSize * valsY[j]) / float(normY))

                # create rectangle
                rect = OWCanvasRectangle(self.canvas,
                                         currX + 2,
                                         currY + 2,
                                         width - 4,
                                         height - 4,
                                         z=-10)
                self.addRectIndependencePearson(rect, currX + 2, currY + 2,
                                                width - 4, height - 4,
                                                (xAttr, xVal), (yAttr, yVal),
                                                actual, sum_)

                expected = float(xVal * yVal) / float(sum_)
                pearson = (actual - expected) / sqrt(expected)
                tooltipText = """<b>X Attribute: %s</b><br>Value: <b>%s</b><br>Number of examples (p(x)): <b>%d (%.2f%%)</b><hr>
                                <b>Y Attribute: %s</b><br>Value: <b>%s</b><br>Number of examples (p(y)): <b>%d (%.2f%%)</b><hr>
                                <b>Number Of Examples (Probabilities):</b><br>Expected (p(x)p(y)): <b>%.1f (%.2f%%)</b><br>Actual (p(x,y)): <b>%d (%.2f%%)</b>
                                <hr><b>Statistics:</b><br>Chi-square: <b>%.2f</b><br>Standardized Pearson residual: <b>%.2f</b>""" % (
                    self.attrX, getHtmlCompatibleString(xAttr), xVal,
                    100.0 * float(xVal) / float(sum_), self.attrY,
                    getHtmlCompatibleString(yAttr), yVal,
                    100.0 * float(yVal) / float(sum_), expected,
                    100.0 * float(xVal * yVal) / float(sum_ * sum_), actual,
                    100.0 * float(actual) / float(sum_), chisquare, pearson)
                rect.setToolTip(tooltipText)

                currY += height
                if currX == xOff:
                    xl = OWCanvasText(self.canvas,
                                      "",
                                      xOff - 10,
                                      currY - height / 2,
                                      Qt.AlignRight | Qt.AlignVCenter,
                                      htmlText=getHtmlCompatibleString(
                                          data.domain[self.attrY].values[j]))
                    max_ylabel_w = max(int(xl.boundingRect().width()),
                                       max_ylabel_w)

            OWCanvasText(self.canvas,
                         "",
                         currX + width / 2,
                         yOff + sqareSize + 5,
                         Qt.AlignCenter,
                         htmlText=getHtmlCompatibleString(
                             data.domain[self.attrX].values[i]))
            currX += width

        # show attribute names
        OWCanvasText(self.canvas,
                     self.attrY,
                     max(xOff - 20 - max_ylabel_w, 20),
                     yOff + sqareSize / 2,
                     Qt.AlignRight | Qt.AlignVCenter,
                     bold=1,
                     vertical=True)
        OWCanvasText(self.canvas,
                     self.attrX,
                     xOff + sqareSize / 2,
                     yOff + sqareSize + 15,
                     Qt.AlignCenter,
                     bold=1)

        #self.canvas.update()

    # create a dictionary with all possible pairs of "combination-of-attr-values" : count
    def getConditionalDistributions(self, data, attrs):
        cond_dist = defaultdict(int)
        all_attrs = [data.domain[a] for a in attrs]
        if data.domain.class_var is not None:
            all_attrs.append(data.domain.class_var)

        for i in range(1, len(all_attrs) + 1):
            attr = all_attrs[:i]
            if type(data) == SqlTable:
                # make all possible pairs of attributes + class_var
                attr = [a.to_sql() for a in attr]
                fields = attr + ["COUNT(*)"]
                query = data._sql_query(fields, group_by=attr)
                with data._execute_sql_query(query) as cur:
                    res = cur.fetchall()
                for r in res:
                    str_values = [
                        a.repr_val(a.to_val(x))
                        for a, x in zip(all_attrs, r[:-1])
                    ]
                    str_values = [
                        x if x != '?' else 'None' for x in str_values
                    ]
                    cond_dist['-'.join(str_values)] = r[-1]
            else:
                for indices in product(*(range(len(a.values)) for a in attr)):
                    vals = []
                    conditions = []
                    for k, ind in enumerate(indices):
                        vals.append(attr[k].values[ind])
                        fd = Orange.data.filter.FilterDiscrete(
                            column=attr[k], values=[attr[k].values[ind]])
                        conditions.append(fd)
                    filt = Orange.data.filter.Values(conditions)
                    filtdata = filt(data)
                    cond_dist['-'.join(vals)] = len(filtdata)
        return cond_dist

    ######################################################################
    ## show deviations from attribute independence with standardized pearson residuals
    def addRectIndependencePearson(self, rect, x, y, w, h, xAttr_xVal,
                                   yAttr_yVal, actual, sum):
        xAttr, xVal = xAttr_xVal
        yAttr, yVal = yAttr_yVal
        expected = float(xVal * yVal) / float(sum)
        pearson = (actual - expected) / sqrt(expected)

        if pearson > 0:  # if there are more examples that we would expect under the null hypothesis
            intPearson = floor(pearson)
            pen = QPen(QColor(0, 0, 255), 1)
            rect.setPen(pen)
            b = 255
            r = g = 255 - intPearson * 20
            r = g = max(r, 55)  #
        elif pearson < 0:
            intPearson = ceil(pearson)
            pen = QPen(QColor(255, 0, 0), 1)
            rect.setPen(pen)
            r = 255
            b = g = 255 + intPearson * 20
            b = g = max(b, 55)
        else:
            pen = QPen(QColor(255, 255, 255), 1)
            r = g = b = 255  # white
        color = QColor(r, g, b)
        brush = QBrush(color)
        rect.setBrush(brush)

        if self.showCases and w > 6 and h > 6:
            if self.showInColor:
                if pearson > 0: c = QColor(0, 0, 255)
                else: c = QColor(255, 0, 0)
            else: c = Qt.black
            for i in range(int(actual)):
                OWCanvasEllipse(self.canvas,
                                random.randint(x + 1, x + w - 4),
                                random.randint(y + 1, y + h - 4),
                                3,
                                3,
                                penColor=c,
                                brushColor=c,
                                z=100)

        if pearson > 0:
            pearson = min(pearson, 10)
            kvoc = 1 - 0.08 * pearson  #  if pearson in [0..10] --> kvoc in [1..0.2]
        else:
            pearson = max(pearson, -10)
            kvoc = 1 - 0.4 * pearson

        self.addLines(x, y, w, h, kvoc, pen)

    ##################################################
    # add lines
    def addLines(self, x, y, w, h, diff, pen):
        if not self.showLines: return
        if w == 0 or h == 0: return

        # create lines
        dist = 20  # original distance between two lines in pixels
        dist = dist * diff
        temp = dist
        while (temp < w):
            OWCanvasLine(self.canvas, temp + x, y, temp + x, y + h, 1,
                         pen.color())
            temp += dist

        temp = dist
        while (temp < h):
            OWCanvasLine(self.canvas, x, y + temp, x + w, y + temp, 1,
                         pen.color())
            temp += dist

    def saveToFileCanvas(self):
        sizeDlg = OWChooseImageSizeDlg(self.canvas, parent=self)
        sizeDlg.exec_()

    def closeEvent(self, ce):
        # self.optimizationDlg.hide()
        QDialog.closeEvent(self, ce)
Esempio n. 2
0
class OWSieveDiagram(OWWidget):
    """
    A two-way contingency table providing information on the relation
    between the observed and expected frequencies of a combination of values
    """
    name = "Sieve Diagram"
    icon = "icons/SieveDiagram.svg"
    priority = 310

    inputs = [("Data", Table, "set_data", Default),
              ("Features", AttributeList, "set_input_features")]
    outputs = [("Selection", Table)]

    graph_name = "canvas"

    want_control_area = False

    settingsHandler = DomainContextHandler()
    attrX = ContextSetting("")
    attrY = ContextSetting("")
    selection = ContextSetting(set())

    def __init__(self):
        # pylint: disable=missing-docstring
        super().__init__()

        self.data = self.discrete_data = None
        self.attrs = []
        self.input_features = None
        self.areas = []
        self.selection = set()

        self.attr_box = gui.hBox(self.mainArea)
        model = VariableListModel()
        model.wrap(self.attrs)
        combo_args = dict(
            widget=self.attr_box, master=self, contentsLength=12,
            callback=self.update_attr, sendSelectedValue=True, valueType=str,
            model=model)
        fixed_size = (QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.attrXCombo = gui.comboBox(value="attrX", **combo_args)
        gui.widgetLabel(self.attr_box, "\u2715", sizePolicy=fixed_size)
        self.attrYCombo = gui.comboBox(value="attrY", **combo_args)
        self.vizrank = SieveRank(self)
        self.vizrank_button = gui.button(
            self.attr_box, self, "Score Combinations", sizePolicy=fixed_size,
            callback=self.vizrank.reshow, enabled=False)
        self.vizrank.pairSelected.connect(self.set_attr)

        self.canvas = QGraphicsScene()
        self.canvasView = ViewWithPress(
            self.canvas, self.mainArea, handler=self.reset_selection)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        box = gui.hBox(self.mainArea)
        box.layout().addWidget(self.graphButton)
        box.layout().addWidget(self.report_button)

    def sizeHint(self):
        return QSize(450, 550)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.update_graph()

    def showEvent(self, event):
        super().showEvent(event)
        self.update_graph()

    def closeEvent(self, event):
        self.vizrank.close()
        super().closeEvent(event)

    def hideEvent(self, event):
        self.vizrank.hide()
        super().hideEvent(event)

    def set_data(self, data):
        """
        Discretize continuous attributes, and put all attributes and discrete
        metas into self.attrs, which is used as a model for combos.

        Select the first two attributes unless context overrides this.
        Method `resolve_shown_attributes` is called to use the attributes from
        the input, if it exists and matches the attributes in the data.

        Remove selection; again let the context override this.
        Initialize the vizrank dialog, but don't show it.

        Args:
            data (Table): input data
        """
        if isinstance(data, SqlTable) and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.closeContext()
        self.data = data
        self.areas = []
        self.selection = set()
        if self.data is None:
            self.attrs[:] = []
        else:
            if any(attr.is_continuous for attr in data.domain):
                discretizer = Discretize(
                    method=EqualFreq(n=4),
                    discretize_classes=True, discretize_metas=True)
                self.discrete_data = discretizer(data)
            else:
                self.discrete_data = self.data
            self.attrs[:] = [
                var for var in chain(
                    self.discrete_data.domain,
                    (var for var in self.data.domain.metas if var.is_discrete))
            ]
        if self.attrs:
            self.attrX = self.attrs[0].name
            self.attrY = self.attrs[len(self.attrs) > 1].name
        else:
            self.attrX = self.attrY = None
            self.areas = []
            self.selection = set()
        self.openContext(self.data)
        self.resolve_shown_attributes()
        self.update_graph()
        self.update_selection()

        self.vizrank.initialize()
        self.vizrank_button.setEnabled(
            self.data is not None and len(self.data) > 1 and
            len(self.data.domain.attributes) > 1)

    def set_attr(self, attr_x, attr_y):
        self.attrX, self.attrY = attr_x.name, attr_y.name
        self.update_attr()

    def update_attr(self):
        """Update the graph and selection."""
        self.selection = set()
        self.update_graph()
        self.update_selection()

    def set_input_features(self, attr_list):
        """
        Handler for the Features signal.

        The method stores the attributes and calls `resolve_shown_attributes`

        Args:
            attr_list (AttributeList): data from the signal
        """
        self.input_features = attr_list
        self.resolve_shown_attributes()
        self.update_selection()

    def resolve_shown_attributes(self):
        """
        Use the attributes from the input signal if the signal is present
        and at least two attributes appear in the domain. If there are
        multiple, use the first two. Combos are disabled if inputs are used.
        """
        self.warning()
        self.attr_box.setEnabled(True)
        if not self.input_features:  # None or empty
            return
        features = [f for f in self.input_features if f in self.attrs]
        if not features:
            self.warning(
                "Features from the input signal are not present in the data")
            return
        old_attrs = self.attrX, self.attrY
        self.attrX, self.attrY = [f.name for f in (features * 2)[:2]]
        self.attr_box.setEnabled(False)
        if (self.attrX, self.attrY) != old_attrs:
            self.selection = set()
            self.update_graph()

    def reset_selection(self):
        self.selection = set()
        self.update_selection()

    def select_area(self, area, event):
        """
        Add or remove the clicked area from the selection

        Args:
            area (QRect): the area that is clicked
            event (QEvent): event description
        """
        if event.button() != Qt.LeftButton:
            return
        index = self.areas.index(area)
        if event.modifiers() & Qt.ControlModifier:
            self.selection ^= {index}
        else:
            self.selection = {index}
        self.update_selection()

    def update_selection(self):
        """
        Update the graph (pen width) to show the current selection.
        Filter and output the data.
        """
        if self.areas is None or not self.selection:
            self.send("Selection", None)
            return

        filts = []
        for i, area in enumerate(self.areas):
            if i in self.selection:
                width = 4
                val_x, val_y = area.value_pair
                filts.append(
                    filter.Values([
                        filter.FilterDiscrete(self.attrX, [val_x]),
                        filter.FilterDiscrete(self.attrY, [val_y])
                    ]))
            else:
                width = 1
            pen = area.pen()
            pen.setWidth(width)
            area.setPen(pen)
        if len(filts) == 1:
            filts = filts[0]
        else:
            filts = filter.Values(filts, conjunction=False)
        selection = filts(self.discrete_data)
        if self.discrete_data is not self.data:
            idset = set(selection.ids)
            sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset]
            selection = self.data[sel_idx]
        self.send("Selection", selection)

    def update_graph(self):
        # Function uses weird names like r, g, b, but it does it with utmost
        # caution, hence
        # pylint: disable=invalid-name
        """Update the graph."""

        def text(txt, *args, **kwargs):
            return CanvasText(self.canvas, "", html_text=to_html(txt),
                              *args, **kwargs)

        def width(txt):
            return text(txt, 0, 0, show=False).boundingRect().width()

        def fmt(val):
            return str(int(val)) if val % 1 == 0 else "{:.2f}".format(val)

        def show_pearson(rect, pearson, pen_width):
            """
            Color the given rectangle according to its corresponding
            standardized Pearson residual.

            Args:
                rect (QRect): the rectangle being drawn
                pearson (float): signed standardized pearson residual
                pen_width (int): pen width (bolder pen is used for selection)
            """
            r = rect.rect()
            x, y, w, h = r.x(), r.y(), r.width(), r.height()
            if w == 0 or h == 0:
                return

            r = b = 255
            if pearson > 0:
                r = g = max(255 - 20 * pearson, 55)
            elif pearson < 0:
                b = g = max(255 + 20 * pearson, 55)
            else:
                r = g = b = 224
            rect.setBrush(QBrush(QColor(r, g, b)))
            pen_color = QColor(255 * (r == 255), 255 * (g == 255),
                               255 * (b == 255))
            pen = QPen(pen_color, pen_width)
            rect.setPen(pen)
            if pearson > 0:
                pearson = min(pearson, 10)
                dist = 20 - 1.6 * pearson
            else:
                pearson = max(pearson, -10)
                dist = 20 - 8 * pearson
            pen.setWidth(1)

            def _offseted_line(ax, ay):
                r = QGraphicsLineItem(x + ax, y + ay, x + (ax or w),
                                      y + (ay or h))
                self.canvas.addItem(r)
                r.setPen(pen)

            ax = dist
            while ax < w:
                _offseted_line(ax, 0)
                ax += dist

            ay = dist
            while ay < h:
                _offseted_line(0, ay)
                ay += dist

        def make_tooltip():
            """Create the tooltip. The function uses local variables from
            the enclosing scope."""
            # pylint: disable=undefined-loop-variable
            def _oper(attr_name, txt):
                if self.data.domain[attr_name] is ddomain[attr_name]:
                    return "="
                return " " if txt[0] in "<≥" else " in "

            return (
                "<b>{attrX}{xeq}{xval_name}</b>: {obs_x}/{n} ({p_x:.0f} %)".
                format(attrX=to_html(attr_x),
                       xeq=_oper(attr_x, xval_name),
                       xval_name=to_html(xval_name),
                       obs_x=fmt(chi.probs_x[x] * n),
                       n=int(n),
                       p_x=100 * chi.probs_x[x]) +
                "<br/>" +
                "<b>{attrY}{yeq}{yval_name}</b>: {obs_y}/{n} ({p_y:.0f} %)".
                format(attrY=to_html(attr_y),
                       yeq=_oper(attr_y, yval_name),
                       yval_name=to_html(yval_name),
                       obs_y=fmt(chi.probs_y[y] * n),
                       n=int(n),
                       p_y=100 * chi.probs_y[y]) +
                "<hr/>" +
                """<b>combination of values: </b><br/>
                   &nbsp;&nbsp;&nbsp;expected {exp} ({p_exp:.0f} %)<br/>
                   &nbsp;&nbsp;&nbsp;observed {obs} ({p_obs:.0f} %)""".
                format(exp=fmt(chi.expected[y, x]),
                       p_exp=100 * chi.expected[y, x] / n,
                       obs=fmt(chi.observed[y, x]),
                       p_obs=100 * chi.observed[y, x] / n))

        for item in self.canvas.items():
            self.canvas.removeItem(item)
        if self.data is None or len(self.data) == 0 or \
                self.attrX is None or self.attrY is None:
            return

        ddomain = self.discrete_data.domain
        attr_x, attr_y = self.attrX, self.attrY
        disc_x, disc_y = ddomain[attr_x], ddomain[attr_y]
        view = self.canvasView

        chi = ChiSqStats(self.discrete_data, attr_x, attr_y)
        n = chi.n
        max_ylabel_w = max((width(val) for val in disc_y.values), default=0)
        max_ylabel_w = min(max_ylabel_w, 200)
        x_off = width(attr_x) + max_ylabel_w
        y_off = 15
        square_size = min(view.width() - x_off - 35, view.height() - y_off - 50)
        square_size = max(square_size, 10)
        self.canvasView.setSceneRect(0, 0, view.width(), view.height())

        curr_x = x_off
        max_xlabel_h = 0
        self.areas = []
        for x, (px, xval_name) in enumerate(zip(chi.probs_x, disc_x.values)):
            if px == 0:
                continue
            width = square_size * px

            curr_y = y_off
            for y in range(len(chi.probs_y) - 1, -1, -1):  # bottom-up order
                py = chi.probs_y[y]
                yval_name = disc_y.values[y]
                if py == 0:
                    continue
                height = square_size * py

                selected = len(self.areas) in self.selection
                rect = CanvasRectangle(
                    self.canvas, curr_x + 2, curr_y + 2, width - 4, height - 4,
                    z=-10, onclick=self.select_area)
                rect.value_pair = x, y
                self.areas.append(rect)
                show_pearson(rect, chi.residuals[y, x], 3 * selected)
                rect.setToolTip(make_tooltip())

                if x == 0:
                    text(yval_name, x_off, curr_y + height / 2,
                         Qt.AlignRight | Qt.AlignVCenter)
                curr_y += height

            xl = text(xval_name, curr_x + width / 2, y_off + square_size,
                      Qt.AlignHCenter | Qt.AlignTop)
            max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h)
            curr_x += width

        bottom = y_off + square_size + max_xlabel_h
        text(attr_y, 0, y_off + square_size / 2,
             Qt.AlignLeft | Qt.AlignVCenter, bold=True, vertical=True)
        text(attr_x, x_off + square_size / 2, bottom,
             Qt.AlignHCenter | Qt.AlignTop, bold=True)
        xl = text("χ²={:.2f}, p={:.3f}".format(chi.chisq, chi.p),
                  0, bottom)
        # Assume similar height for both lines
        text("N = " + fmt(chi.n), 0, bottom - xl.boundingRect().height())

    def get_widget_name_extension(self):
        if self.data is not None:
            return "{} vs {}".format(self.attrX, self.attrY)

    def send_report(self):
        self.report_plot()
Esempio n. 3
0
class Level(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self,parent)

        self.filename = QString()
        self.copiedItem = QByteArray()
        self.pasteOffset = 5
        self.prevPoint = QPoint()
        self.addOffset = 5
        
        self.screenSize = (320, 240)
        self.bgColor = QColor(244,244,244)
        '''0.Portrait 1.Landscape'''
        self.orientation = 0
        self.currentItem = None
        

        self.printer = QPrinter(QPrinter.HighResolution)
        self.printer.setPageSize(QPrinter.Letter)


        '''1.Header'''
        self.levelBar = LevelBar(self)
        
        '''3.Tiler'''
        self.tiler = TileMapGrid(self)#Tiler(self)
        self.tiler.setMinimumHeight(100)
        #self.tiler.currentChanged.connect(self.closeDesigner)
        #self.tiler.setTabsClosable(True)
        #self.tiler.setTabShape(0)
        #self.tiler.hide()
        #self.levelLayout.addWidget(self.levelBar) 
        
        '''2.view'''
        viewLayoutWidget = QFrame()
        viewLayoutWidget.setFrameShape(QFrame.StyledPanel)
        viewLayout = QHBoxLayout(viewLayoutWidget)
        #viewLayout.setMargin(10)
        self.view = LevelView(viewLayoutWidget)
        '''scene'''
        self.scene = QGraphicsScene(self)
        #self.scene.selectionChanged.connect(self.setConnect)
        #self.view.setStyleSheet("border: 1px solid red;")
        
        self.setBackgroundColor(self.bgColor)
        self.setScreenSize(self.screenSize)
        
        self.view.setScene(self.scene)
        self.view.setAlignment(Qt.AlignCenter)
        self.scroll_off = 1
        self.setScrollBar()
        
        viewLayout.setMargin(0)
        viewLayout.addWidget(self.view)

        self.wrapped = [] # Needed to keep wrappers alive
        layout = QVBoxLayout(self)
        layout.addWidget(self.levelBar)
        layout.addWidget(viewLayoutWidget)
        layout.addWidget(self.tiler)
        layout.setMargin(0)
        self.setLayout(layout)
        
    def setScrollBar(self):
        if(self.scroll_off):
            self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.scroll_off = 0
        else:
            self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            self.scroll_off = 1
        
    def setBackgroundColor(self,color):
        self.bgColor = color
        self.scene.setBackgroundBrush(QBrush(color))
        
    def setScreenSize(self,size):
        self.screenSize = size
        self.setOrientation(self.orientation)
        
    def setOrientation(self,idx):
        self.orientation = idx
        if(idx == 0):
            self.view.setMaximumSize(self.screenSize[1], self.screenSize[0])
            self.scene.setSceneRect(0, 0, self.screenSize[1], self.screenSize[0])
        else:
            self.view.setMaximumSize(self.screenSize[0], self.screenSize[1])
            self.scene.setSceneRect(0, 0, self.screenSize[0], self.screenSize[1])
        
    def offerSave(self):
        if (Dirty and QMessageBox.question(self,
                            "Designer - Unsaved Changes",
                            "Save unsaved changes?",
                            QMessageBox.Yes|QMessageBox.No) == 
           QMessageBox.Yes):
            self.save()


    def position(self):
        point = self.mapFromGlobal(QCursor.pos())
        if not self.view.geometry().contains(point):
            coord = random.randint(36, 144)
            point = QPoint(coord, coord)
        else:
            if point == self.prevPoint:
                point += QPoint(self.addOffset, self.addOffset)
                self.addOffset += 5
            else:
                self.addOffset = 5
                self.prevPoint = point
        return self.view.mapToScene(point)
    
    def selectedItem(self):
        items = self.scene.selectedItems()
        if len(items) == 1:
            return items[0]
        return None
    
    def current(self,item):
        self.scene.clearSelection()
        sceneItems = self.scene.items()
        for items in sceneItems:
            if(items != item):
                item.setSelected(False)
                if(item.isConnected()):
                    self.propertyBar.disconnectText(item)
                    item.setConnected(False)
        self.currentItem = item
        self.currentItem.setConnected(True)
        self.currentItem.setSelected(True)
        self.propertyBar.connectText(self.currentItem)
        self.propertyBar.initText(self.currentItem)


    def addText(self):
        item = TextItem("SomeText", self.position())
        self.connect(item, SIGNAL("current"),self.current)
        self.connect(item, SIGNAL("copy"),self.copy)
        self.connect(item, SIGNAL("cut"),self.cut)
        self.connect(item, SIGNAL("paste"),self.paste)
        self.connect(item, SIGNAL("delete"),self.delete)
        #self.current(item)
        self.scene.addItem(item)
        

    def copy(self):
        item = self.selectedItem()
        if item is None:
            return
        self.copiedItem.clear()
        self.pasteOffset = 5
        stream = QDataStream(self.copiedItem, QIODevice.WriteOnly)
        self.writeItemToStream(stream, item)


    def cut(self):
        item = self.selectedItem()
        if item is None:
            return
        self.copy()
        self.scene.removeItem(item)
        del item


    def paste(self):
        if self.copiedItem.isEmpty():
            return
        stream = QDataStream(self.copiedItem, QIODevice.ReadOnly)
        item = self.readItemFromStream(stream, self.pasteOffset)
        self.pasteOffset += 5
        #self.scene.addItem(item)
        
    def delete(self):
        items = self.scene.selectedItems()
        if (len(items) and QMessageBox.question(self,
                "Designer - Delete",
                "Delete {0} item{1}?".format(len(items),
                "s" if len(items) != 1 else ""),
                QMessageBox.Yes|QMessageBox.No) ==
                QMessageBox.Yes):
            while items:
                item = items.pop()
                self.scene.removeItem(item)
                del item
                
    def readItemFromStream(self, stream, offset=0):
        type = QString()
        position = QPointF()
        matrix = QMatrix()
        stream >> type >> position >> matrix
        if offset:
            position += QPointF(offset, offset)
        if type == "Text":
            text = QString()
            font = QFont()
            stream >> text >> font
            self.scene.addItem(TextItem(text, position, font, matrix))
        elif type == "Box":
            rect = QRectF()
            stream >> rect
            style = Qt.PenStyle(stream.readInt16())
            self.scene.addItem(BoxItem(position, style, matrix))
        elif type == "Pixmap":
            pixmap = QPixmap()
            stream >> pixmap
            self.scene.addItem(self.createPixmapItem(pixmap, position, matrix))


    def writeItemToStream(self, stream, item):
        if isinstance(item, QGraphicsTextItem):
            stream << QString("Text") << item.pos() \
                   << item.matrix() << item.toPlainText() << item.font()
        elif isinstance(item, QGraphicsPixmapItem):
            stream << QString("Pixmap") << item.pos() \
                   << item.matrix() << item.pixmap()
        elif isinstance(item, BoxItem):
            stream << QString("Box") << item.pos() \
                   << item.matrix() << item.rect
            stream.writeInt16(item.style)

    def rotate(self):
        for item in self.scene.selectedItems():
            item.rotate(30)


    def print_(self):
        dialog = QPrintDialog(self.printer)
        if dialog.exec_():
            painter = QPainter(self.printer)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setRenderHint(QPainter.TextAntialiasing)
            self.scene.clearSelection()
            #self.removeBorders()
            self.scene.render(painter)
            #self.addBorders()


    def open(self):
        self.offerSave()
        path = (QFileInfo(self.filename).path()
                if not self.filename.isEmpty() else ".")
        fname = QFileDialog.getOpenFileName(self,
                "Page Designer - Open", path,
                "Page Designer Files (*.pgd)")
        if fname.isEmpty():
            return
        self.filename = fname
        fh = None
        try:
            fh = QFile(self.filename)
            if not fh.open(QIODevice.ReadOnly):
                raise IOError, unicode(fh.errorString())
            items = self.scene.items()
            while items:
                item = items.pop()
                self.scene.removeItem(item)
                del item
            self.addBorders()
            stream = QDataStream(fh)
            stream.setVersion(QDataStream.Qt_4_2)
            magic = stream.readInt32()
            if magic != MagicNumber:
                raise IOError, "not a valid .pgd file"
            fileVersion = stream.readInt16()
            if fileVersion != FileVersion:
                raise IOError, "unrecognised .pgd file version"
            while not fh.atEnd():
                self.readItemFromStream(stream)
        except IOError, e:
            QMessageBox.warning(self, "Page Designer -- Open Error",
                    "Failed to open {0}: {1}".format(self.filename, e))
        finally:
Esempio n. 4
0
class MainForm(QDialog):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)
        self.Running = False
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, SCENESIZEX, SCENESIZEY)
        self.view = QGraphicsView()
        self.view.setRenderHint(QPainter.Antialiasing)
        self.view.setScene(self.scene)
        self.view.setFocusPolicy(Qt.NoFocus)
        #self.zoomSlider = QSlider(Qt.Horizontal)
        #self.zoomSlider.setRange(5, 200)
        #self.zoomSlider.setValue(100)
        self.pauseButton = QPushButton("Pa&use")
        self.quitButton = QPushButton("&Quit")

        layout = QVBoxLayout()
        layout.addWidget(self.view)
        #layout.addWidget(self.zoomSlider)
        layout.addWidget(self.pauseButton)
        layout.addWidget(self.quitButton)
        self.setLayout(layout)

        #self.connect(self.zoomSlider, SIGNAL("valueChanged(int))"),
        #             self.zoom)
        self.connect(self.pauseButton, SIGNAL("clicked()"),
                     self.pauseOrResume)
        self.connect(self.quitButton, SIGNAL("clicked()"), self.accept)
        
        self.readNodes()
        self.zoom(1.0)
        self.populate()
        #self.startTimer(INTERVAL)
        self.setWindowTitle("TdPaleo")
        
    def pauseOrResume(self):
        self.Running = not self.Running
        self.pauseButton.setText("Pa&use" if self.Running else "Res&ume")
        items = self.scene.items()
        for item in items:
            item.setRunning()
    
    def zoom(self, value):
        factor =1/ 1.5
        matrix = self.view.matrix()
        matrix.reset()
        matrix.scale(factor, factor)
        self.view.setMatrix(matrix)
    
    def readNodes(self):
        file = open("tdp_geometry.dat")
        file.readline()
        while True:
            line = file.readline()
            if not line:
                break
            param = line.split(" ")
            if (line != "\n"):
                n = node()
                n.x = float(param[0])
                n.y = 956 - float(param[1])
                n.angle = float(param[2])
                n.d = int(param[3])
                n.type = int(param[4])
                nodes.append(n)

    def populate(self):
        color = QColor(0, 150, 0)
        head = TdPCavallo(color, nodes[0].angle, QPointF(nodes[0].x, nodes[0].y))
        #FIXME AGGIUNGERE POI IL FANTINO AL CAVALLO
        #segment = Segment(color, offset, head)
        self.scene.addItem(head)
        #Running = False
        
    def timerEvent(self, event):
        if not self.Running:
            return
class NostraIllustCheckDlg(QtGui.QDialog, FORM_CLASS):
    def __init__(self, theCanvas, theLayer, selFeatureIds, parent=None):
        super(NostraIllustCheckDlg, self).__init__(parent)
        self.setupUi(self)
        self.mTheCanvas = theCanvas
        self.mTheLayer = theLayer
        self.mSelFeatureIds = selFeatureIds
        self.mAllFeatureIds = []
        self.highlightList = []
        uri = QgsDataSourceURI(self.mTheLayer.source())
        self.conn = psycopg2.connect('''host='%s' dbname='%s' user='******' password='******' ''' %\
            (uri.host(), uri.database(), uri.username(), uri.password()))
        self.pg = self.conn.cursor()

        # members shown in graphic view.
        self.mScene = QGraphicsScene()
        self.graphicsViewShowImage.setScene(self.mScene)
        self.mPixmapList = []

        featureIter = self.mTheLayer.getFeatures(QgsFeatureRequest().setFlags(
            QgsFeatureRequest.NoGeometry))
        inti = 0
        theFeature = QgsFeature()
        while (featureIter.nextFeature(theFeature)):
            inti += 1
            self.mAllFeatureIds.append(theFeature.id())

        self.spinBoxFeatureIndex.setValue(1)
        self.spinBoxFeatureIndex.setMinimum(1)
        self.spinBoxFeatureIndex.setMaximum(inti)

        errMsg = ['']
        self.initComboBoxOutlinkid()
        self.selectFeatureById(errMsg,
                               self.mSelFeatureIds[0],
                               bZoomToSelected=False)
        self.comboBoxOutlinkid.setFocus()

        self.pushButtonPrev.clicked.connect(self.onPushButtonPrev)
        self.pushButtonNext.clicked.connect(self.onPushButtonNext)
        self.connect(self.comboBoxOutlinkid,
                     QtCore.SIGNAL('activated(QString)'),
                     self.comboBoxOutlinkidChanged)

    def resizeEvent(self, event):
        self.showImageInGraphicsView()
        return

    def disableAllControls(self):
        self.pushButtonPrev.setEnabled(False)
        self.pushButtonPrev.setEnabled(False)
        self.comboBoxOutlinkid.setEnabled(False)
        self.textEditFeatureInfo.setEnabled(False)
        return

    def initComboBoxOutlinkid(self):
        while (self.comboBoxOutlinkid.count() > 0):
            self.comboBoxOutlinkid.removeItem(0)
        for oneFeatureId in self.mSelFeatureIds:
            featureIter = self.mTheLayer.getFeatures(
                QgsFeatureRequest(oneFeatureId).setFlags(
                    QgsFeatureRequest.NoGeometry))
            theFeature = QgsFeature()
            if featureIter.nextFeature(theFeature) == False:
                return
            if self.mIsMyFeature(theFeature):
                strTemp = "%.0f, %.0f" % (theFeature.attribute('arc1'),
                                          theFeature.attribute('arc2'))
                self.comboBoxOutlinkid.addItem(strTemp)

    def showFeatureDetail(self, errMsg, theFeature):
        strFeatureInfo = self.getFeatureInfoString(theFeature)
        self.textEditFeatureInfo.setText(strFeatureInfo)
        if self.mIsMyFeature(theFeature) == False:
            return

        errMsg = ['']
        day_pic = theFeature.attribute('day_pic')
        arrowimg = theFeature.attribute('arrowimg')
        basePath = r"\\tangpinghui\20151010_nostra_junctionview\output_jpg_and_png"
        day_pic_path = os.path.join(basePath, day_pic + ".psd\Main_Day.jpg")
        arrowimg_path = ''
        tempPath = os.path.join(basePath, day_pic + ".psd")
        for curDir, subDirs, fileNames in os.walk(tempPath):
            for oneFile in fileNames:
                if oneFile.find(arrowimg) != -1 and oneFile.find('_en') != -1:
                    arrowimg_path = os.path.join(curDir, oneFile)

        self.mPixmapList = []
        patternPixmap = QPixmap()
        patternPixmap.load(day_pic_path)
        self.mPixmapList.append(patternPixmap)
        arrowPixmap = QPixmap()
        arrowPixmap.load(arrowimg_path)
        self.mPixmapList.append(arrowPixmap)
        self.showImageInGraphicsView()
        return

    def showImageInGraphicsView(self):
        # remove all items in member QGraphicsScene.
        for oneItem in self.mScene.items():
            self.mScene.removeItem(oneItem)

        for onePixmap in self.mPixmapList:
            self.mScene.addPixmap(
                self.getPixMapSizedByWidgt(onePixmap,
                                           self.graphicsViewShowImage))

        self.mScene.setSceneRect(0, 0,
                                 self.graphicsViewShowImage.width() - 5,
                                 self.graphicsViewShowImage.height() - 5)
        return

    def getFeatureInfoString(self, theFeature):
        fieldList = theFeature.fields()
        attrList = theFeature.attributes()
        strFeatureInfo = "field count: %d\n" % len(fieldList)
        for oneField, oneAttr in zip(fieldList, attrList):
            if isinstance(oneAttr, float):
                strFeatureInfo += "%s: %.0f\n" % (oneField.name(), oneAttr)
            else:
                strFeatureInfo += "%s: %s\n" % (oneField.name(), oneAttr)
        return strFeatureInfo

    def comboBoxOutlinkidChanged(self, txt):
        errMsg = ['']
        inti = self.comboBoxOutlinkid.currentIndex()
        self.selectFeatureById(errMsg,
                               self.mSelFeatureIds[inti],
                               bZoomToSelected=False)
        if errMsg[0] <> '':
            QMessageBox.information(self, "Nostra Illust Check",
                                    """error:\n%s""" % errMsg[0])
            return
        return

    def onPushButtonPrev(self):
        self.spinBoxFeatureIndex.setValue(self.spinBoxFeatureIndex.value() - 1)
        prevFeatureId = self.mAllFeatureIds[self.spinBoxFeatureIndex.value() -
                                            1]
        errMsg = ['']
        self.selectFeatureById(errMsg, prevFeatureId)
        if errMsg[0] <> '':
            QMessageBox.information(self, "Nostra Illust Check",
                                    """error:\n%s""" % errMsg[0])
            return
        return

    def onPushButtonNext(self):
        self.spinBoxFeatureIndex.setValue(self.spinBoxFeatureIndex.value() + 1)
        nextFeatureId = self.mAllFeatureIds[self.spinBoxFeatureIndex.value() -
                                            1]
        errMsg = ['']
        self.selectFeatureById(errMsg, nextFeatureId)
        if errMsg[0] <> '':
            QMessageBox.information(self, "Nostra Illust Check",
                                    """error:\n%s""" % errMsg[0])
            return
        return

    def selectFeatureById(self, errMsg, featureId, bZoomToSelected=True):
        self.mTheLayer.removeSelection()
        self.mTheLayer.select(featureId)
        theFeature = self.mTheLayer.selectedFeatures()[0]
        self.showFeatureDetail(errMsg, theFeature)
        if errMsg[0] <> '':
            return
        if bZoomToSelected == True:
            center = self.mTheCanvas.panToSelected(self.mTheLayer)
            self.mTheCanvas.refresh()
        self.clearHighlight()
        arc1 = "%.0f" % theFeature.attribute('arc1')
        sqlcmd = """
SET bytea_output TO escape;
select st_asbinary(the_geom) from temp_topo_link where routeid=%s
""" % arc1
        self.pg.execute(sqlcmd)
        rows = self.pg.fetchall()
        for row in rows:
            qgsGeometry = QgsGeometry()
            qgsGeometry.fromWkb(str(row[0]))
            self.highlightByGeometry(qgsGeometry, QColor(249, 27, 15, 168))

        arc2 = "%.0f" % theFeature.attribute('arc2')
        sqlcmd = """
SET bytea_output TO escape;
select st_asbinary(the_geom) from temp_topo_link where routeid=%s
""" % arc2
        self.pg.execute(sqlcmd)
        rows = self.pg.fetchall()
        for row in rows:
            qgsGeometry = QgsGeometry()
            qgsGeometry.fromWkb(str(row[0]))
            self.highlightByGeometry(qgsGeometry, QColor(22, 151, 0, 168))

        new_arc1 = "%.0f" % theFeature.attribute('new_arc1')
        if new_arc1 is not None and new_arc1 <> arc1:
            sqlcmd = """
SET bytea_output TO escape;
select st_asbinary(the_geom) from temp_topo_link where routeid=%s
""" % new_arc1
            self.pg.execute(sqlcmd)
            rows = self.pg.fetchall()
            for row in rows:
                qgsGeometry = QgsGeometry()
                qgsGeometry.fromWkb(str(row[0]))
                self.highlightByGeometry(qgsGeometry,
                                         QColor(253, 158, 153, 128))

        new_arc2 = "%.0f" % theFeature.attribute('new_arc2')
        if new_arc2 is not None and new_arc2 <> arc2:
            sqlcmd = """
SET bytea_output TO escape;
select st_asbinary(the_geom) from temp_topo_link where routeid=%s
""" % new_arc2
            self.pg.execute(sqlcmd)
            rows = self.pg.fetchall()
            for row in rows:
                qgsGeometry = QgsGeometry()
                qgsGeometry.fromWkb(str(row[0]))
                self.highlightByGeometry(qgsGeometry,
                                         QColor(147, 255, 155, 128))

        return

    def getPixMapSizedByWidgt(self, pixmap, theWidgt):
        pixmapWidth = pixmap.width()
        pixmapHeight = pixmap.height()
        gpViewWidth = theWidgt.width()
        gpViewHeight = theWidgt.height()

        destWidth = 0
        destHeight = 0
        if pixmapWidth > gpViewWidth - 5:
            destWidth = gpViewWidth - 5
        else:
            destWidth = pixmapWidth

        if pixmapHeight > gpViewHeight - 5:
            destHeight = gpViewHeight - 5
        else:
            destHeight = pixmapHeight

        return pixmap.scaled(destWidth, destHeight,
                             QtCore.Qt.IgnoreAspectRatio,
                             QtCore.Qt.SmoothTransformation)

    def mIsMyFeature(self, theFeature):
        return NostraIllustCheckDlg.isMyFeature(theFeature)

    @staticmethod
    def isMyFeature(theFeature):
        try:
            gid = theFeature.attribute('gid')
            arc1 = theFeature.attribute('arc1')
            arc2 = theFeature.attribute('arc2')
            day_pic = theFeature.attribute('day_pic')
            night_pic = theFeature.attribute('night_pic')
            arrowimg = theFeature.attribute('arrowimg')
            lon = theFeature.attribute('lon')
            lat = theFeature.attribute('lat')
            new_arc1 = theFeature.attribute('new_arc1')
            new_arc2 = theFeature.attribute('new_arc2')
        except KeyError, kErr:
            return False
        except Exception, ex:
            return False
Esempio n. 6
0
class PaintArea(QGraphicsView):
    def __init__(self, parent):
        QGraphicsView.__init__(self)
        self.init(parent)
        self.initShape()
        self.initCall = 2
        self.minimumWidth = 550
        self.setEnabled(False)

    def init(self, parent):
        self.timeline = parent
        self.pixmap = None
        self.image = None

    def initShape(self):
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setAlignment(Qt.AlignLeft)
        self.clicStart = None
        self.selectionRect = None

    def resizeEvent(self, sizEvent):
        if self.selectionRect and self.scene:
            self.scene.removeItem(self.selectionRect)
            self.selectionRect = None
            self.clicStart = None

        self.width = sizEvent.size().width()
        self.height = sizEvent.size().height()

        if self.initCall > 0:
            self.timeline.options.setMaximumWidth(
                self.timeline.options.minimumSizeHint().width())
            self.initCall -= 1

        if self.width < self.minimumWidth:
            self.timeline.setStateInfo('Unable to draw - Not enought width')
        else:
            self.timeline.workerThread.render()

    def mousePressEvent(self, mouseEvent):
        self.clicStart = mouseEvent.pos()
        if self.clicStart.x() < self.timeline.draw.yLeftMargin - 1:
            self.clicStart.setX(self.timeline.draw.yLeftMargin - 1)
        if self.clicStart.x(
        ) > self.timeline.ploter.width - self.timeline.m + 1:
            self.clicStart.setX(self.timeline.ploter.width - self.timeline.m +
                                1)

        if self.selectionRect:
            for item in self.scene.items():
                if str(type(
                        item)) == "<class 'PyQt4.QtGui.QGraphicsRectItem'>":
                    self.scene.removeItem(item)
            self.selectionRect = None
            self.timeline.options.zoomButton.setEnabled(False)
            self.timeline.options.exportButton.setEnabled(False)
            self.timeline.options.selectedNodes.setText('Nothing selected')
            if self.timeline.selDateMin:
                self.timeline.options.selStartTime.setText('From ' + str(
                    self.timeline.fromUSec(self.timeline.baseDateMin).strftime(
                        '%d.%m.%Y %H:%M:%S')))
                self.timeline.options.selEndTime.setText('To ' + str(
                    self.timeline.fromUSec(self.timeline.baseDateMax).strftime(
                        '%d.%m.%Y %H:%M:%S')))
            else:
                self.timeline.options.selStartTime.setText(
                    'No selection start time')
                self.timeline.options.selEndTime.setText(
                    'No selection end time')
            self.timeline.options.selectedNodes.setText('Nothing selected')

    def mouseMoveEvent(self, dragMoveEvent):
        if self.clicStart:
            if self.clicStart.x() < dragMoveEvent.x():
                x = self.clicStart.x()
                w = dragMoveEvent.x() - self.clicStart.x()
            else:
                x = dragMoveEvent.x()
                w = self.clicStart.x() - dragMoveEvent.x()

# Limit rectangle to selectable area
            if x < self.timeline.draw.yLeftMargin - 1:
                x = self.timeline.draw.yLeftMargin - 1
                w = self.clicStart.x() - x
            if x > self.timeline.ploter.width - self.timeline.m + 1:
                x = self.timeline.ploter.width - self.timeline.m + 1
                w = 0
            if x + w > self.timeline.ploter.width - self.timeline.m + 1:
                w = ((self.timeline.ploter.width - self.timeline.m + 1) - x)

            y = (self.timeline.m / 3) - 1
            h = self.height - self.timeline.m - self.timeline.m / 3 + 2
            if self.selectionRect and self.scene:
                self.scene.removeItem(self.selectionRect)
            self.selectionRect = self.scene.addRect(QRectF(x, y, w, h),
                                                    QPen(Qt.DashDotDotLine))

    def mouseReleaseEvent(self, mouseEvent):
        if self.selectionRect:
            if self.clicStart.x() > mouseEvent.x():
                x1 = mouseEvent.x()
                x2 = self.clicStart.x()
            else:
                x1 = self.clicStart.x()
                x2 = mouseEvent.x()
            self.timeline.nodesInRange(x1, x2)
            start = self.timeline.draw.findXTime(x1)
            if start:
                self.timeline.options.selStartTime.setText(
                    'From ' + str(start.strftime('%d.%m.%Y %H:%M:%S')))
            end = self.timeline.draw.findXTime(x2)
            if end:
                self.timeline.options.selEndTime.setText(
                    'To ' + str(end.strftime('%d.%m.%Y %H:%M:%S')))
Esempio n. 7
0
class MainForm(QDialog):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)
        self.Running = False
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, SCENESIZEX, SCENESIZEY)
        self.view = QGraphicsView()
        self.view.setRenderHint(QPainter.Antialiasing)
        self.view.setScene(self.scene)
        self.view.setFocusPolicy(Qt.NoFocus)
        #self.zoomSlider = QSlider(Qt.Horizontal)
        #self.zoomSlider.setRange(5, 200)
        #self.zoomSlider.setValue(100)
        self.pauseButton = QPushButton("Pa&use")
        self.quitButton = QPushButton("&Quit")

        layout = QVBoxLayout()
        layout.addWidget(self.view)
        #layout.addWidget(self.zoomSlider)
        layout.addWidget(self.pauseButton)
        layout.addWidget(self.quitButton)
        self.setLayout(layout)

        #self.connect(self.zoomSlider, SIGNAL("valueChanged(int))"),
        #             self.zoom)
        self.connect(self.pauseButton, SIGNAL("clicked()"), self.pauseOrResume)
        self.connect(self.quitButton, SIGNAL("clicked()"), self.accept)

        self.readNodes()
        self.zoom(1.0)
        self.populate()
        #self.startTimer(INTERVAL)
        self.setWindowTitle("TdPaleo")

    def pauseOrResume(self):
        self.Running = not self.Running
        self.pauseButton.setText("Pa&use" if self.Running else "Res&ume")
        items = self.scene.items()
        for item in items:
            item.setRunning()

    def zoom(self, value):
        factor = 1 / 1.5
        matrix = self.view.matrix()
        matrix.reset()
        matrix.scale(factor, factor)
        self.view.setMatrix(matrix)

    def readNodes(self):
        file = open("tdp_geometry.dat")
        file.readline()
        while True:
            line = file.readline()
            if not line:
                break
            param = line.split(" ")
            if (line != "\n"):
                n = node()
                n.x = float(param[0])
                n.y = 956 - float(param[1])
                n.angle = float(param[2])
                n.d = int(param[3])
                n.type = int(param[4])
                nodes.append(n)

    def populate(self):
        color = QColor(0, 150, 0)
        head = TdPCavallo(color, nodes[0].angle,
                          QPointF(nodes[0].x, nodes[0].y))
        #FIXME AGGIUNGERE POI IL FANTINO AL CAVALLO
        #segment = Segment(color, offset, head)
        self.scene.addItem(head)
        #Running = False

    def timerEvent(self, event):
        if not self.Running:
            return
Esempio n. 8
0
class OWSieveDiagram(OWWidget):
    name = "Sieve Diagram"
    icon = "icons/SieveDiagram.svg"
    priority = 4200

    inputs = [("Data", Table, "setData", Default),
              ("Features", AttributeList, "setShownAttributes")]
    outputs = []

    settingsList = ["showLines", "showCases", "showInColor"]
    def __init__(self,parent=None, signalManager = None):
        OWWidget.__init__(self, parent, signalManager, "Sieve diagram", True)

        #self.controlArea.setMinimumWidth(250)

        #set default settings
        self.data = None

        self.attrX = ""
        self.attrY = ""
        self.attrCondition = ""
        self.attrConditionValue = ""
        self.showLines = 1
        self.showCases = 0
        self.showInColor = 1
        self.attributeSelectionList = None
        self.stopCalculating = 0

        self.canvas = QGraphicsScene()
        self.canvasView = QGraphicsView(self.canvas, self.mainArea)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        #GUI
        self.attrSelGroup = gui.widgetBox(self.controlArea, box = "Shown attributes")

        self.attrXCombo = gui.comboBox(self.attrSelGroup, self, value="attrX", label="X attribute:", orientation="horizontal", tooltip = "Select an attribute to be shown on the X axis", callback = self.updateGraph, sendSelectedValue = 1, valueType = str, labelWidth = 70)
        self.attrYCombo = gui.comboBox(self.attrSelGroup, self, value="attrY", label="Y attribute:", orientation="horizontal", tooltip = "Select an attribute to be shown on the Y axis", callback = self.updateGraph, sendSelectedValue = 1, valueType = str, labelWidth = 70)

        gui.separator(self.controlArea)

        self.conditionGroup = gui.widgetBox(self.controlArea, box = "Condition")
        self.attrConditionCombo      = gui.comboBox(self.conditionGroup, self, value="attrCondition", label="Attribute:", orientation="horizontal", callback = self.updateConditionAttr, sendSelectedValue = 1, valueType = str, labelWidth = 70)
        self.attrConditionValueCombo = gui.comboBox(self.conditionGroup, self, value="attrConditionValue", label="Value:", orientation="horizontal", callback = self.updateGraph, sendSelectedValue = 1, valueType = str, labelWidth = 70)

        gui.separator(self.controlArea)

        box2 = gui.widgetBox(self.controlArea, box = "Visual settings")
        gui.checkBox(box2, self, "showLines", "Show lines", callback = self.updateGraph)
        hbox = gui.widgetBox(box2, orientation = "horizontal")
        gui.checkBox(hbox, self, "showCases", "Show data examples...", callback = self.updateGraph)
        gui.checkBox(hbox, self, "showInColor", "...in color", callback = self.updateGraph)

        gui.separator(self.controlArea)
        # self.optimizationDlg = OWSieveOptimization(self, self.signalManager)
        # optimizationButtons = gui.widgetBox(self.controlArea, "Dialogs", orientation = "horizontal")
        # gui.button(optimizationButtons, self, "VizRank", callback = self.optimizationDlg.reshow, debuggingEnabled = 0, tooltip = "Find attribute groups with highest value dependency")

        gui.rubber(self.controlArea)

        # self.wdChildDialogs = [self.optimizationDlg]        # used when running widget debugging
        # self.graphButton.clicked.connect(self.saveToFileCanvas)
        self.icons = gui.attributeIconDict
        self.resize(800, 550)
        random.seed()

    def sendReport(self):
        self.startReport("%s [%s, %s]" % (self.windowTitle(), self.attrX, self.attrY))
        self.reportSettings("",
                            [("X-Attribute", self.attrX), ("Y-Attribute", self.attrY),
                             self.attrCondition != "(None)" and ("Condition", "%s = '%s'" % (self.attrCondition, self.attrConditionValue))])
        # self.reportImage(lambda *x: OWChooseImageSizeDlg(self.canvas).saveImage(*x))


    # receive new data and update all fields
    def setData(self, data):
        if type(data) == SqlTable and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.information(0)
        self.information(1)
        sameDomain = self.data and data and self.data.domain.checksum() == data.domain.checksum() # preserve attribute choice if the domain is the same
        # self.data = self.optimizationDlg.setData(data, 0)
        self.data = data

        self.warning(0, "")
        if data:
            if any(isinstance(attr, ContinuousVariable) for attr in data.domain):
                self.warning(0, "Data contains continuous variables. " +
                             "Discretize the data to use them.")

        if not sameDomain:
            self.initCombos()

        self.setShownAttributes(self.attributeSelectionList)

    ## Attribute selection signal
    def setShownAttributes(self, attrList):
        self.attributeSelectionList = attrList
        if self.data and self.attributeSelectionList and len(attrList) >= 2:
            attrs = [attr.name for attr in self.data.domain]
            if attrList[0] in attrs and attrList[1] in attrs:
                self.attrX = attrList[0]
                self.attrY = attrList[1]
        self.updateGraph()



    # create data subset depending on conditional attribute and value
    def getConditionalData(self, xAttr = None, yAttr = None, dropMissingData = 1):
        if not self.data: return None

        if not xAttr: xAttr = self.attrX
        if not yAttr: yAttr = self.attrY
        if not (xAttr and yAttr): return

        if self.attrCondition == "(None)":
            data = self.data[:, [xAttr, yAttr]]
            # data = self.data.select([xAttr, yAttr])
        else:
            # data = orange.Preprocessor_dropMissing(self.data.select([xAttr, yAttr, self.attrCondition]))
            # data = self.data.select({self.attrCondition:self.attrConditionValue})
            fd = Orange.data.filter.FilterDiscrete(column=self.attrCondition, values=[self.attrConditionValue])
            filt = Orange.data.filter.Values([fd])
            filt.domain = self.data.domain
            data = filt(self.data)

        # if dropMissingData: return orange.Preprocessor_dropMissing(data)
        #else:
        return data

    # new conditional attribute was set - update graph
    def updateConditionAttr(self):
        self.attrConditionValueCombo.clear()

        if self.attrCondition != "(None)":
            for val in self.data.domain[self.attrCondition].values:
                self.attrConditionValueCombo.addItem(val)
            self.attrConditionValue = str(self.attrConditionValueCombo.itemText(0))
        self.updateGraph()

    # initialize lists for shown and hidden attributes
    def initCombos(self):
        self.attrXCombo.clear()
        self.attrYCombo.clear()
        self.attrConditionCombo.clear()
        self.attrConditionCombo.addItem("(None)")
        self.attrConditionValueCombo.clear()

        if not self.data: return
        for i, var in enumerate(self.data.domain):
            if isinstance(var, DiscreteVariable):
                self.attrXCombo.addItem(self.icons[self.data.domain[i]], self.data.domain[i].name)
                self.attrYCombo.addItem(self.icons[self.data.domain[i]], self.data.domain[i].name)
                self.attrConditionCombo.addItem(self.icons[self.data.domain[i]], self.data.domain[i].name)
        self.attrCondition = str(self.attrConditionCombo.itemText(0))

        if self.attrXCombo.count() > 0:
            self.attrX = str(self.attrXCombo.itemText(0))
            self.attrY = str(self.attrYCombo.itemText(self.attrYCombo.count() > 1))

    def resizeEvent(self, e):
        OWWidget.resizeEvent(self,e)
        self.updateGraph()

    def showEvent(self, ev):
        OWWidget.showEvent(self, ev)
        self.updateGraph()

    ## updateGraph - gets called every time the graph has to be updated
    def updateGraph(self, *args):
        for item in self.canvas.items():
            self.canvas.removeItem(item)    # remove all canvas items
        if not self.data: return
        if not self.attrX or not self.attrY: return

        data = self.getConditionalData()
        if not data or len(data) == 0: return

        valsX = []
        valsY = []
        # contX = orange.ContingencyAttrAttr(self.attrX, self.attrX, data)   # distribution of X attribute
        # contY = orange.ContingencyAttrAttr(self.attrY, self.attrY, data)   # distribution of Y attribute
        contX = get_contingency(data, self.attrX, self.attrX)
        contY = get_contingency(data, self.attrY, self.attrY)

        # compute contingency of x and y attributes
        for entry in contX:
            sum_ = 0
            try:
                for val in entry: sum_ += val
            except: pass
            valsX.append(sum_)

        for entry in contY:
            sum_ = 0
            try:
                for val in entry: sum_ += val
            except: pass
            valsY.append(sum_)

        # create cartesian product of selected attributes and compute contingency
        # (cart, profit) = FeatureByCartesianProduct(data, [data.domain[self.attrX], data.domain[self.attrY]])
        # tempData = data.select(list(data.domain) + [cart])
        # contXY = orange.ContingencyAttrAttr(cart, cart, tempData)   # distribution of X attribute
        # contXY = get_contingency(tempData, cart, cart)
        contXY = self.getConditionalDistributions(data, [data.domain[self.attrX], data.domain[self.attrY]])

        # compute probabilities
        probs = {}
        for i in range(len(valsX)):
            valx = valsX[i]
            for j in range(len(valsY)):
                valy = valsY[j]

                actualProb = 0
                try:
                    actualProb = contXY['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                    # for val in contXY['%s-%s' %(i, j)]: actualProb += val
                except:
                    actualProb = 0
                probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])] = ((data.domain[self.attrX].values[i], valx), (data.domain[self.attrY].values[j], valy), actualProb, len(data))

        # get text width of Y attribute name
        text = OWCanvasText(self.canvas, data.domain[self.attrY].name, x  = 0, y = 0, bold = 1, show = 0, vertical=True)
        xOff = int(text.boundingRect().height() + 40)
        yOff = 50
        sqareSize = min(self.canvasView.width() - xOff - 35, self.canvasView.height() - yOff - 30)
        if sqareSize < 0: return    # canvas is too small to draw rectangles
        self.canvasView.setSceneRect(0, 0, self.canvasView.width(), self.canvasView.height())

        # print graph name
        if self.attrCondition == "(None)":
            name  = "<b>P(%s, %s) &#8800; P(%s)&times;P(%s)</b>" %(self.attrX, self.attrY, self.attrX, self.attrY)
        else:
            name = "<b>P(%s, %s | %s = %s) &#8800; P(%s | %s = %s)&times;P(%s | %s = %s)</b>" %(self.attrX, self.attrY, self.attrCondition, getHtmlCompatibleString(self.attrConditionValue), self.attrX, self.attrCondition, getHtmlCompatibleString(self.attrConditionValue), self.attrY, self.attrCondition, getHtmlCompatibleString(self.attrConditionValue))
        OWCanvasText(self.canvas, "" , xOff+ sqareSize/2, 20, Qt.AlignCenter, htmlText = name)
        OWCanvasText(self.canvas, "N = " + str(len(data)), xOff+ sqareSize/2, 38, Qt.AlignCenter, bold = 0)

        ######################
        # compute chi-square
        chisquare = 0.0
        for i in range(len(valsX)):
            for j in range(len(valsY)):
                ((xAttr, xVal), (yAttr, yVal), actual, sum_) = probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                expected = float(xVal*yVal)/float(sum_)
                if expected == 0: continue
                pearson2 = (actual - expected)*(actual - expected) / expected
                chisquare += pearson2

        ######################
        # draw rectangles
        currX = xOff
        max_ylabel_w = 0

        normX, normY = sum(valsX), sum(valsY)
        for i in range(len(valsX)):
            if valsX[i] == 0: continue
            currY = yOff
            width = int(float(sqareSize * valsX[i])/float(normX))
            
            #for j in range(len(valsY)):
            for j in range(len(valsY)-1, -1, -1):   # this way we sort y values correctly
                ((xAttr, xVal), (yAttr, yVal), actual, sum_) = probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                if valsY[j] == 0: continue
                height = int(float(sqareSize * valsY[j])/float(normY))

                # create rectangle
                rect = OWCanvasRectangle(self.canvas, currX+2, currY+2, width-4, height-4, z = -10)
                self.addRectIndependencePearson(rect, currX+2, currY+2, width-4, height-4, (xAttr, xVal), (yAttr, yVal), actual, sum_)

                expected = float(xVal*yVal)/float(sum_)
                pearson = (actual - expected) / sqrt(expected)
                tooltipText = """<b>X Attribute: %s</b><br>Value: <b>%s</b><br>Number of examples (p(x)): <b>%d (%.2f%%)</b><hr>
                                <b>Y Attribute: %s</b><br>Value: <b>%s</b><br>Number of examples (p(y)): <b>%d (%.2f%%)</b><hr>
                                <b>Number Of Examples (Probabilities):</b><br>Expected (p(x)p(y)): <b>%.1f (%.2f%%)</b><br>Actual (p(x,y)): <b>%d (%.2f%%)</b>
                                <hr><b>Statistics:</b><br>Chi-square: <b>%.2f</b><br>Standardized Pearson residual: <b>%.2f</b>""" %(self.attrX, getHtmlCompatibleString(xAttr), xVal, 100.0*float(xVal)/float(sum_), self.attrY, getHtmlCompatibleString(yAttr), yVal, 100.0*float(yVal)/float(sum_), expected, 100.0*float(xVal*yVal)/float(sum_*sum_), actual, 100.0*float(actual)/float(sum_), chisquare, pearson )
                rect.setToolTip(tooltipText)

                currY += height
                if currX == xOff:
                    xl = OWCanvasText(self.canvas, "", xOff - 10, currY - height/2, Qt.AlignRight | Qt.AlignVCenter, htmlText = getHtmlCompatibleString(data.domain[self.attrY].values[j]))
                    max_ylabel_w = max(int(xl.boundingRect().width()), max_ylabel_w)

            OWCanvasText(self.canvas, "", currX + width/2, yOff + sqareSize + 5, Qt.AlignCenter, htmlText = getHtmlCompatibleString(data.domain[self.attrX].values[i]))
            currX += width

        # show attribute names
        OWCanvasText(self.canvas, self.attrY, max(xOff-20-max_ylabel_w, 20), yOff + sqareSize/2, Qt.AlignRight | Qt.AlignVCenter, bold = 1, vertical=True)
        OWCanvasText(self.canvas, self.attrX, xOff + sqareSize/2, yOff + sqareSize + 15, Qt.AlignCenter, bold = 1)

        #self.canvas.update()

    # create a dictionary with all possible pairs of "combination-of-attr-values" : count
    def getConditionalDistributions(self, data, attrs):
        cond_dist = defaultdict(int)
        all_attrs = [data.domain[a] for a in attrs]
        if data.domain.class_var is not None:
            all_attrs.append(data.domain.class_var)

        for i in range(1, len(all_attrs) + 1):
            attr = all_attrs[:i]
            if type(data) == SqlTable:
                # make all possible pairs of attributes + class_var
                attr = [a.to_sql() for a in attr]
                fields = attr + ["COUNT(*)"]
                query = data._sql_query(fields, group_by=attr)
                with data._execute_sql_query(query) as cur:
                    res = cur.fetchall()
                for r in res:
                    str_values =[a.repr_val(a.to_val(x)) for a, x in zip(all_attrs, r[:-1])]
                    str_values = [x if x != '?' else 'None' for x in str_values]
                    cond_dist['-'.join(str_values)] = r[-1]
            else:
                for indices in product(*(range(len(a.values)) for a in attr)):
                    vals = []
                    conditions = []
                    for k, ind in enumerate(indices):
                        vals.append(attr[k].values[ind])
                        fd = Orange.data.filter.FilterDiscrete(column=attr[k], values=[attr[k].values[ind]])
                        conditions.append(fd)
                    filt = Orange.data.filter.Values(conditions)
                    filtdata = filt(data)
                    cond_dist['-'.join(vals)] = len(filtdata)
        return cond_dist

    ######################################################################
    ## show deviations from attribute independence with standardized pearson residuals
    def addRectIndependencePearson(self, rect, x, y, w, h, xAttr_xVal, yAttr_yVal, actual, sum):
        xAttr, xVal = xAttr_xVal
        yAttr, yVal = yAttr_yVal
        expected = float(xVal*yVal)/float(sum)
        pearson = (actual - expected) / sqrt(expected)

        if pearson > 0:     # if there are more examples that we would expect under the null hypothesis
            intPearson = floor(pearson)
            pen = QPen(QColor(0,0,255), 1); rect.setPen(pen)
            b = 255
            r = g = 255 - intPearson*20
            r = g = max(r, 55)  #
        elif pearson < 0:
            intPearson = ceil(pearson)
            pen = QPen(QColor(255,0,0), 1)
            rect.setPen(pen)
            r = 255
            b = g = 255 + intPearson*20
            b = g = max(b, 55)
        else:
            pen = QPen(QColor(255,255,255), 1)
            r = g = b = 255         # white
        color = QColor(r,g,b)
        brush = QBrush(color); rect.setBrush(brush)

        if self.showCases and w > 6 and h > 6:
            if self.showInColor:
                if pearson > 0: c = QColor(0,0,255)
                else: c = QColor(255, 0,0)
            else: c = Qt.black
            for i in range(int(actual)):
                OWCanvasEllipse(self.canvas, random.randint(x+1, x + w-4), random.randint(y+1, y + h-4), 3, 3, penColor = c, brushColor = c, z = 100)

        if pearson > 0:
            pearson = min(pearson, 10)
            kvoc = 1 - 0.08 * pearson       #  if pearson in [0..10] --> kvoc in [1..0.2]
        else:
            pearson = max(pearson, -10)
            kvoc = 1 - 0.4*pearson

        self.addLines(x,y,w,h, kvoc, pen)


    ##################################################
    # add lines
    def addLines(self, x,y,w,h, diff, pen):
        if not self.showLines: return
        if w == 0 or h == 0: return

        # create lines
        dist = 20   # original distance between two lines in pixels
        dist = dist * diff
        temp = dist
        while (temp < w):
            OWCanvasLine(self.canvas, temp+x, y, temp+x, y+h, 1, pen.color())
            temp += dist

        temp = dist
        while (temp < h):
            OWCanvasLine(self.canvas, x, y+temp, x+w, y+temp, 1, pen.color())
            temp += dist

    def saveToFileCanvas(self):
        sizeDlg = OWChooseImageSizeDlg(self.canvas, parent=self)
        sizeDlg.exec_()

    def closeEvent(self, ce):
        # self.optimizationDlg.hide()
        QDialog.closeEvent(self, ce)
class SpotguideShowImageDlg(QtGui.QDialog, FORM_CLASS):
    def __init__(self, theCanvas, theLayer, selFeatureIds, parent=None):
        super(SpotguideShowImageDlg, self).__init__(parent)
        self.setupUi(self)
        self.mTheCanvas = theCanvas
        self.mTheLayer = theLayer
        self.mSelFeatureIds = selFeatureIds
        self.mAllFeatureIds = []
        self.highlightList = []

        # members shown in graphic view.
        self.mScene = QGraphicsScene()
        self.graphicsViewShowImage.setScene(self.mScene)
        self.mPixmapList = []

        featureIter = self.mTheLayer.getFeatures(QgsFeatureRequest().setFlags(
            QgsFeatureRequest.NoGeometry))
        inti = 0
        theFeature = QgsFeature()
        while (featureIter.nextFeature(theFeature) and inti < 512):
            inti += 1
            self.mAllFeatureIds.append(theFeature.id())

        self.spinBoxFeatureIndex.setValue(1)
        self.spinBoxFeatureIndex.setMinimum(1)
        self.spinBoxFeatureIndex.setMaximum(inti)

        errMsg = ['']
        self.initComboBoxOutlinkid()
        self.selectFeatureById(errMsg,
                               self.mSelFeatureIds[0],
                               bZoomToSelected=False)
        self.comboBoxOutlinkid.setFocus()

        self.pushButtonPrev.clicked.connect(self.onPushButtonPrev)
        self.pushButtonNext.clicked.connect(self.onPushButtonNext)
        self.connect(self.comboBoxOutlinkid,
                     QtCore.SIGNAL('activated(QString)'),
                     self.comboBoxOutlinkidChanged)

    def resizeEvent(self, event):
        self.showImageInGraphicsView()
        return

    def disableAllControls(self):
        self.pushButtonPrev.setEnabled(False)
        self.pushButtonPrev.setEnabled(False)
        self.comboBoxOutlinkid.setEnabled(False)
        self.textEditFeatureInfo.setEnabled(False)
        return

    def initComboBoxOutlinkid(self):
        while (self.comboBoxOutlinkid.count() > 0):
            self.comboBoxOutlinkid.removeItem(0)
        for oneFeatureId in self.mSelFeatureIds:
            featureIter = self.mTheLayer.getFeatures(
                QgsFeatureRequest(oneFeatureId).setFlags(
                    QgsFeatureRequest.NoGeometry))
            theFeature = QgsFeature()
            if featureIter.nextFeature(theFeature) == False:
                return
            if self.mIsMyFeature(theFeature):
                self.comboBoxOutlinkid.addItem(
                    str(theFeature.attribute('out_link_id')))

    def showFeatureDetail(self, errMsg, theFeature):
        strFeatureInfo = self.getFeatureInfoString(theFeature)
        self.textEditFeatureInfo.setText(strFeatureInfo)
        if self.mIsMyFeature(theFeature) == False:
            return

        errMsg = ['']
        pattern_dat, arrow_dat = self.getSpotguidePictures(
            errMsg, self.mTheLayer, theFeature)
        if errMsg[0] != '':
            #QMessageBox.information(self, "Show Spotguide", errMsg[0])
            return

        self.mPixmapList = []
        if pattern_dat is not None:
            patternDatParser = DatParser()
            patternDatParser.initFromMemory(errMsg,
                                            pattern_dat)  # pattern picture
            patternPixmap = QPixmap()
            patternPixmap.loadFromData(
                patternDatParser.getDatContentByIndex(errMsg, 0))
            self.mPixmapList.append(patternPixmap)

        if arrow_dat is not None:
            arrowDatParser = DatParser()
            arrowDatParser.initFromMemory(errMsg, arrow_dat)  # arrow picture
            arrowPixmap = QPixmap()
            arrowPixmap.loadFromData(
                arrowDatParser.getDatContentByIndex(errMsg, 0))
            if arrowDatParser.hasPointlist():
                # draw the point list on the arrow picture
                vecCoors = arrowDatParser.getPointListCoordinatesByIndex(
                    errMsg, arrowDatParser.getPointlistIndex())
                if errMsg[0] != '':
                    QMessageBox.information(self, "Show Spotguide", errMsg[0])
                    return
                with QPainter(arrowPixmap) as thePainter:
                    for oneXYPair in vecCoors:
                        thePainter.setPen(QPen(QColor(255, 0, 0)))
                        thePainter.drawPoint(oneXYPair[0], oneXYPair[1])
                        thePainter.drawPoint(oneXYPair[0] - 1, oneXYPair[1])
                        thePainter.drawPoint(oneXYPair[0] + 1, oneXYPair[1])
                        thePainter.drawPoint(oneXYPair[0], oneXYPair[1] - 1)
                        thePainter.drawPoint(oneXYPair[0], oneXYPair[1] + 1)

                # append pointlist information to the text box.
                strPointList = arrowDatParser.getPointListStringByIndex(
                    errMsg, arrowDatParser.getPointlistIndex())
                if errMsg[0] != '':
                    QMessageBox.information(self, "Show Spotguide", errMsg[0])
                    return
                strTemp = self.textEditFeatureInfo.toPlainText()
                strTemp += """\n\npointlist:\n"""
                strTemp += strPointList
                self.textEditFeatureInfo.setText(strTemp)
            self.mPixmapList.append(arrowPixmap)

        self.showImageInGraphicsView()
        return

    def showImageInGraphicsView(self):
        # remove all items in member QGraphicsScene.
        for oneItem in self.mScene.items():
            self.mScene.removeItem(oneItem)

        for onePixmap in self.mPixmapList:
            self.mScene.addPixmap(
                self.getPixMapSizedByWidgt(onePixmap,
                                           self.graphicsViewShowImage))

        self.mScene.setSceneRect(0, 0,
                                 self.graphicsViewShowImage.width() - 5,
                                 self.graphicsViewShowImage.height() - 5)
        return

    def getFeatureInfoString(self, theFeature):
        fieldList = theFeature.fields()
        attrList = theFeature.attributes()
        strFeatureInfo = "field count: %d\n" % len(fieldList)
        for oneField, oneAttr in zip(fieldList, attrList):
            if isinstance(oneAttr, float):
                strFeatureInfo += "%s: %.0f\n" % (oneField.name(), oneAttr)
            else:
                strFeatureInfo += "%s: %s\n" % (oneField.name(), oneAttr)
        return strFeatureInfo

    # result[0] is pattern dat
    # result[1] is arrow dat
    def getSpotguidePictures(self, errMsg, layer, theFeature):
        try:
            uri = QgsDataSourceURI(layer.source())
            conn = psycopg2.connect('''host='%s' dbname='%s' user='******' password='******' ''' %\
                (uri.host(), uri.database(), uri.username(), uri.password()))
            pg = conn.cursor()

            # all these lane's keys must be found
            # if anyone is not found, a 'KeyError' exception will be thrown.
            in_link_id = theFeature.attribute('in_link_id')
            node_id = theFeature.attribute('node_id')
            out_link_id = theFeature.attribute('out_link_id')
            passlink_count = theFeature.attribute('passlink_count')
            pattern_id = theFeature.attribute('pattern_id')
            arrow_id = theFeature.attribute('arrow_id')

            # spotguide record filter.
            strFilter = '''in_link_id=%s and node_id=%s and out_link_id=%s and 
                           passlink_count=%s and pattern_id=%s and arrow_id=%s''' % \
                        (in_link_id, node_id, out_link_id, passlink_count, pattern_id, arrow_id)

            sqlcmd = \
"""SET bytea_output TO escape;
select pattern_dat, arrow_dat
from %s
where %s
""" % (uri.table(), strFilter)
            pg.execute(sqlcmd)
            row = pg.fetchone()
            return row[0], row[1]
        except KeyError, kErr:
            errMsg[0] = """Selected feature is not a rdb spotguide feature."""
            return None, None
        except Exception, ex:
            errMsg[0] = ex.message
            return None, None
Esempio n. 10
0
class MainForm(QDialog):

    def __init__(self, parent=None, filename=None):
        super(MainForm, self).__init__(parent)

        self.view = GraphicsView()
        background = QPixmap(filename)

        self.filename = os.path.splitext(filename)[0]
        if ("-%s" % ORG) in self.filename:
            self.filename = self.filename[:-len(ORG)-5] + ".png"

        self.view.setBackgroundBrush(QBrush(background))
        # self.view.setCacheMode(QGraphicsView.CacheBackground)
        # self.view.setDragMode(QGraphicsView.ScrollHandDrag)

        self.scene = QGraphicsScene(self)
        global scene
        scene = self.scene
        self.view.dialog = self
        self.view.setScene(self.scene)
        self.prevPoint = QPoint()
        self.lastStamp = -1 

        buttonLayout = QVBoxLayout()
        for text, slot in (
                ("&Tag", self.addTag),
                ("Align &bottom", self.alignBottom),
                ("Align &left", self.alignLeft),
                ("&Save", self.save),
                ("&Quit", self.accept)):
            button = QPushButton(text)
            if not MAC:
                button.setFocusPolicy(Qt.NoFocus)
            self.connect(button, SIGNAL("clicked()"), slot)
            if text == "&Save":
                buttonLayout.addStretch(5)
            if text == "&Quit":
                buttonLayout.addStretch(1)
            buttonLayout.addWidget(button)
        buttonLayout.addStretch()

        self.view.resize(background.width(), background.height())
        self.scene.setSceneRect(0, 0, background.size().width(), background.size().height())
        self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        layout = QHBoxLayout()
        layout.addWidget(self.view, 1)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)

        self.setWindowTitle(AppName)
        
        info_name = self.filename + "-" + TAG + ".txt"
            
        if os.path.exists(info_name):
            for tag, x, y in [line.strip().split("\t") for line in open(info_name, "rt").readlines()]:
                self.addTag(int(tag), QPointF(int(x), int(y)), adjust_position=False)
        global Dirty; Dirty=False
        self.show()
        self.raise_()

    def reject(self):
        self.accept()

    def accept(self):
        self.offerSave()
        QDialog.accept(self)
        
    def offerSave(self):
        if (Dirty and QMessageBox.question(self, "%s - Unsaved Changes" % AppName, "Save unsaved changes?", 
                                           QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes):
            self.save()

    def position(self):
        return QPointF(self.view.mapFromGlobal(QCursor.pos()))
    
    def addTag(self, stamp=None, position=None, adjust_position=True):
        if not position: position = self.position()
        if stamp is not None:
            self.lastStamp = stamp
        else:
            self.lastStamp += 1
        item = StampItem(self.lastStamp, position, self.scene, adjust_position=adjust_position)
        item.update()
        global Dirty; Dirty = True

    def save(self):
        vals = sorted([(item.stamp, item.pos().x(), item.pos().y()) for item in self.scene.items() if isinstance(item, StampItem)])
        info_name = "%s-%s.txt" %(self.filename, TAG)
        f = open(info_name, "wt")
        for tag, x, y in vals:
            f.write("%s\t%d\t%d\n" % (tag, x, y))
        f.close()
        save_png(self.filename, [(x-5, y-5) for _, x, y in vals])
        global Dirty; Dirty = False
        
    def renumberTags(self):
        """Number the tags by skipping the missing values"""
        vals = sorted([(item.stamp, item) for item in self.scene.items() if isinstance(item, StampItem)])
        for i, (_, v) in enumerate(vals):
            v.setStamp(i)
        if not vals: i = -1
        self.lastStamp = i
        global Dirty; Dirty = True
        
    def alignBottom(self):
        """Align tags horizontally, use bottom margin as a reference"""
        items = [item for item in self.scene.selectedItems() if isinstance(item, StampItem)]
        if items:
            ref_y = max(item.pos().y() for item in items)
            for item in items:
                item.setY(ref_y)
            global Dirty; Dirty = True
                
    def alignLeft(self):
        """Align tags vertically, use left margin as a reference"""
        items = [item for item in self.scene.selectedItems() if isinstance(item, StampItem)]
        if items:
            ref_x = min(item.pos().x() for item in items)
            for item in items:
                item.setX(ref_x)
            global Dirty; Dirty = True
Esempio n. 11
0
class MainForm(QDialog):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)
        
        self.filename = QString()
        self.scene = QGraphicsScene(self)
        self.view = GraphicsView(self.scene)

        self.view.setScene(self.scene)
        buttonLayout = QVBoxLayout()
        for text, slot in (
                ("&Open", self.addPixmap),
                ("&Quit", self.accept)):
            button = QPushButton(text)
            self.connect(button, SIGNAL("clicked()"), slot)
            if text == "&Quit":
                buttonLayout.addStretch(1)
            buttonLayout.addWidget(button)
        buttonLayout.addStretch()
        layout = QHBoxLayout()
        layout.addWidget(self.view, 1)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)
        self.setWindowTitle("Petal Picker")

    def addPixmap(self):
        path = (QFileInfo(self.filename).path()
                if not self.filename.isEmpty() else ".")
        fname = QFileDialog.getOpenFileName(self,
                "Add Pixmap", path,
                "Pixmap Files (*.bmp *.jpg *.png *.xpm)")
        if fname.isEmpty(): return
        self.createPixmapItem(QPixmap(fname))


    def createPixmapItem(self, pixmap, matrix=QMatrix()):
        global PIX
        item = QGraphicsPixmapItem(pixmap)
        PIX = item
#        item.setFlags(QGraphicsItem.ItemIsSelectable|
#                      QGraphicsItem.ItemIsMovable)
        item.setMatrix(matrix)
        self.scene.clearSelection()
        
        for i in self.scene.items():
            self.scene.removeItem(i)
        
        self.scene.addItem(item)
        self.view.fitInView(item,Qt.KeepAspectRatio)
        
        
        global DIRTY
        DIRTY = True
        
    def accept(self):
        global DIRTY
        if not DIRTY: QDialog.accept(self)
        if DIRTY:
            if self.confirm(): QDialog.accept(self)
            else: return

    def confirm(self):
        global DIRTY
        if (DIRTY and QMessageBox.question(self,
                            "Really Quit?",
                            "Really Quit?",
                            QMessageBox.Yes|QMessageBox.No) ==
            QMessageBox.Yes): return True
        else: return False
Esempio n. 12
0
class GraphicsWidget(QWidget):

    def __init__(self, parent=None):
        QWidget.__init__(self)

        self._ui = Ui_Form()
        self._ui.setupUi(self)

        self.commits = {}
        self.commits["first"] =  ["aaaaa", "bbbbb", "ccccc", "ddddd"]
        self.commits["second"] = ["ggggg", "bbbbb", "xxxxx", "aaaaa"]

        self.scene = QGraphicsScene(self)
        self.view = self._ui.graphicsView
        self.view.setScene(self.scene)
        self.view.setRenderHint(QPainter.Antialiasing)
        self.matching_commits = False
        self.view.setAcceptDrops(True)

        self.populate()

    def populate(self):
        self.temp_del_items = []
        self.commit_items = []

        self.filter = my_env_filter()
        self.scene.installEventFilter(self.filter)

        self.hints = Hints(0, -60)
        self.scene.addItem(self.hints)
        item_x = 0
        color = GREEN
        for branch in self.commits:
            item_y = 0

            for commit_name in self.commits[branch]:
                commit = Commit(commit_name)
                commit_background_item = CommitItem(item_x, item_y, 
                                                    color, commit, branch,
                                                    background_item=True)
                arrow = Arrow(item_x, item_y, commit_background_item)
                commit_display_item = CommitItem(item_x, item_y,
                                                 color, commit, branch,
                                                 background_item=False)

                self.scene.addItem(commit_display_item)
                self.scene.addItem(commit_background_item)
                self.commit_items.append(commit_background_item)

                item_y += COMMIT_HEIGHT + ARROW_HEIGHT

            item_x += 270
            color = BLUE

        self.connect_signals()

    def clear_scene(self):
        self.temp_del_items = self.scene.items()
        for item in self.temp_del_items:
            self.scene.removeItem(item)
#            del item

    def set_matching_commits_mode(self, bool):
        print "setting matching"
        self.matching_commits = bool
        if bool:
            self.hints.setup_display(step=1)
            self.hints.update()
        else:
            self.commit_item_finished_hovering()

    def connect_signals(self):
        self.connect(self.filter, SIGNAL("setMatchingMode(bool)"),
                     self.set_matching_commits_mode)

        for commit_item in self.commit_items:
            self.connect(commit_item,
                         SIGNAL("hoveringOverCommitItem(QString*)"),
                         self.commit_item_hovered)
            self.connect(commit_item,
                         SIGNAL("finishedHovering(void)"),
                         self.commit_item_finished_hovering)
            self.connect(commit_item,
                         SIGNAL("commitItemInserted(QString*, QString*)"),
                         self.insert_commit)

    def insert_commit(self, name, branch):
        self.clear_scene()
        self.commits[str(branch)].append(name)
        print self.commits
        self.populate()

    def commit_item_hovered(self, commit_name):
        if self.matching_commits:
            self.hints.setup_display(step=2)
            self.hints.update()
            for commit_item in self.commit_items:
                if commit_item.get_name() != commit_name:
                    commit_item.gray(True)

    def commit_item_finished_hovering(self):
        for commit_item in self.commit_items:
            commit_item.gray(False)
Esempio n. 13
0
class Nexus(QMainWindow):
	"""
	Die Hauptklasse des Programms.

	In dieser Klasse wird die GUI gesteuert und die Würfelwürfe aufgerufen.
	"""
	
	dicePoolChanged = pyqtSignal(int)

	xAgainChanged = pyqtSignal(int)
	cursed = pyqtSignal(bool)


	def __init__(self,  parent=None):
		"""
		Konstruktor 
		"""

		self.translator_app = QTranslator()
		self.translator_qt = QTranslator()

		QApplication.installTranslator( self.translator_app )
		QApplication.installTranslator( self.translator_qt )

		QWidget.__init__(self,  parent)

		QCoreApplication.setOrganizationName("Caern")
		QCoreApplication.setOrganizationDomain("www.caern.de")
		QCoreApplication.setApplicationName("DiceRoller WoD")
		QCoreApplication.setApplicationVersion(QString.number(PROGRAM_VERSION_MAJOR) +
			"." +
			QString.number(PROGRAM_VERSION_MINOR) +
			"." +
			QString.number(PROGRAM_VERSION_CHANGE)
		)
		QApplication.setWindowIcon(QIcon(":/icons/logo/WoD.png"))

		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)
		
		self.createInfo()

		#self.createLanguageMenu()
		self.instantRoll = InstantRoll()
		self.extendedRoll = ExtendedRoll()

		# Dieser Zähler bestimmt, wie der rollende Würfel angezeigt wird.
		self.timerDice = QTimer()
		# Verzögert die tatsächliche Ausführung des Würfelwurfs.
		self.timerRoll = QTimer()
		
		self.populateUi()
		self.createConnections()
		self.initializing()

		self.setWindowTitle(QCoreApplication.applicationName())

		#self.retranslateUi()
		
		## Die von der letzten Benutzung gespeicherte Größe und Position auf dem Bildschirm laden.
		#self.readSettings()


	#def closeEvent(self, event):
		#"""
		#Diese Funktion wird aufgerufen, wann immer das Programm geschlossen wird.
		#Die Idee dahinter ist, vor dem Beenden, Größe und Position des Fensters zu speichern.
		#"""
		#self.writeSettings()
		#event.accept()


	def createInfo(self):
		"""
		Erzeugt Tooltips und Hilfe für die einzelnen Teile des Programms.
		"""

		self.ui.action_houserules.setStatusTip(self.ui.action_houserules.toolTip())


	#def createLanguageMenu(self):
		#"""
		#Erzeugt das Menü zum Umschalten zwischen den möglichen Sprachen.
		#"""

		#self.menu_language = QMenu( self.tr("&Language") )
		#self.actionGroup_language = QActionGroup(self)

		#self.langPath = getPath() + "/" + PROGRAM_LANGUAGE_PATH
		#self.dir_qm = QDir( self.langPath );
		#self.fileNames = self.dir_qm.entryList( QStringList( "DiceRoller-WoD_*.qm" ));

		## Englisch hat keine qm-Datei,  also muß es von Hand hinzugefügt werden.
		#self.action = QAction( "&1 English",  self.actionGroup_language )
		#self.action.setCheckable( True )
		#self.action.setData( "en" )
		#self.action.setChecked( True )

		#self.menu_language.addAction( self.action )
		#self.actionGroup_language.addAction( self.action )

		#iter = 0
		#for i in self.fileNames:
			#self.trFilename = unicode(i)
			#self.locale = unicode(i)
			#self.locale = self.locale[(self.locale.find( "_" )+1):(self.locale.find( "." ))]

			#self.translator = QTranslator()
			#self.translator.load( self.trFilename,  self.dir_qm.absolutePath() )
			#self.language = self.translator.translate( "MainWindow",  "English" )

			#self.action = QAction( "&" + QString.number(iter + 2) + " " + self.language,  self.actionGroup_language )
			#self.action.setCheckable( True )
			#self.action.setData( self.locale )

			#self.menu_language.addAction ( self.action )
			#self.actionGroup_language.addAction ( self.action )

			#iter += 1

		#self.actionGroup_language.triggered.connect(self.switchLanguage)

		#self.ui.menuBar.insertMenu(self.ui.menuHelp.menuAction(),  self.menu_language)


	#def switchLanguage( self,  action ):
		#"""
		#Schaltet zwischen den einzelnen Sprachen um.
		#"""

		#self.locale = action.data().toString();
		#self.qmPath = getPath() + "/" + PROGRAM_LANGUAGE_PATH

		##if self.translator_app.load( "DiceRoller-WoD_" + self.locale,  self.qmPath ):
			##qDebug("Hat DiceRoller-WoD_" + self.locale + " geladen.")

		##if self.translator_qt.load( "qt_" + self.locale,  QLibraryInfo.location ( QLibraryInfo.TranslationsPath ) ):
			##qDebug("Hat qt_" + self.locale + " geladen.")

		## Alle Texte neu setzen
		#self.retranslateUi()
		## Seltsamerweise ist retranslate in Ui_MainWindow leer. Ich weiß nicht,  wieso das der Fall ist.
		#self.ui.retranslateUi(self.ui)


	#def retranslateUi(self):
		#"""
		#Diese Funktion übersetzt alle Texte, welche nicht in der .ui-Datei festgelegt sind, sondern im Quellcode (hier) geschrieben wurden.
		#"""

		#self.menu_language.setTitle( self.tr( "&Language" ) )
		#self.reset()


	def populateUi(self):
		self.svgRenderer = QSvgRenderer(":/icons/W10.svg")
		self.scene = QGraphicsScene()
		self.view = QGraphicsView()
		self.view.setFrameShape(QFrame.NoFrame)
		self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
		self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
		self.view.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
		self.view.setStyleSheet("background-color: transparent;");
		
		self.view.setScene(self.scene)
		self.ui.horizontalLayout_dice.insertWidget(1, self.view)


	def createConnections(self):
		"""
		Erstelle die Verbindungen zwischen den verschiedenen Klassen und Elementen des Programms.
		"""

		self.ui.action_about.triggered.connect(self.aboutApp)
		self.ui.action_aboutQt.triggered.connect(QApplication.aboutQt)
		self.ui.action_houserules.toggled.connect(self.setHouserules)
		self.ui.pushButton_roll.clicked.connect(self.roll)
		self.ui.spinBox_pool.valueChanged.connect(self.calcDicePool)
		self.ui.spinBox_pool.valueChanged.connect(self.reset)
		self.ui.spinBox_modifier.valueChanged.connect(self.calcDicePoolMod)
		self.ui.spinBox_modifier.valueChanged.connect(self.reset)
		self.ui.checkBox_rote.toggled.connect(self.instantRoll.setRote)
		self.ui.checkBox_rote.toggled.connect(self.extendedRoll.setRote)
		self.ui.checkBox_rote.toggled.connect(self.reset)
		self.ui.comboBox_xAgain.activated.connect(self.setXAgainThreshold)
		self.ui.comboBox_xAgain.activated.connect(self.reset)
		self.ui.groupBox_extended.toggled.connect(self.changeText)
		self.ui.radioButton_target.toggled.connect(self.changeText)
		self.ui.radioButton_maxRolls.toggled.connect(self.changeText)
		self.ui.groupBox_extended.toggled.connect(self.reset)
		self.ui.radioButton_target.toggled.connect(self.setExtendedMode)
		self.ui.spinBox_target.valueChanged.connect(self.extendedRoll.setTarget)
		self.ui.spinBox_target.valueChanged.connect(self.reset)
		self.ui.spinBox_maxRolls.valueChanged.connect(self.extendedRoll.setMaxRolls)
		self.ui.spinBox_maxRolls.valueChanged.connect(self.reset)
		self.ui.checkBox_rollsLimited.toggled.connect(self.extendedRoll.setLimited)
		self.ui.checkBox_rollsLimited.toggled.connect(self.reset)
		self.xAgainChanged.connect(self.instantRoll.setThreshold)
		self.xAgainChanged.connect(self.extendedRoll.setThreshold)
		self.cursed.connect(self.instantRoll.setCurse)
		self.cursed.connect(self.extendedRoll.setCurse)
		self.instantRoll.rolled.connect(self.setResultSuccesses)
		self.extendedRoll.rolled.connect(self.setResultSuccesses)
		self.extendedRoll.rollsNeeded.connect(self.setResultRolls)
		self.instantRoll.rollFinished.connect(self.setResult)
		self.extendedRoll.rollFinished.connect(self.setResult)
		
		self.dicePoolChanged.connect(self.changeDiceDisplay)

		self.timerDice.timeout.connect(self.displayDice)
		self.timerRoll.timeout.connect(self._executeRoll)


	def initializing(self):
		"""
		Initialisiert das Programm mit den Startwerten.
		"""

		self.ui.action_quit.setIcon(QIcon(":/icons/actions/exit.png"))
		self.ui.action_about.setIcon(QIcon(":/icons/logo/WoD.png"))
		self.ui.pushButton_quit.setIcon(self.ui.action_quit.icon())
		self.ui.pushButton_roll.setIcon(QIcon(":icons/W10_0.svg"))
		
		self.ui.action_quit.setMenuRole(QAction.QuitRole)
		self.ui.action_about.setText(self.tr("About %1...").arg(QApplication.applicationName()))
		self.ui.action_about.setMenuRole(QAction.AboutRole)

		self.ui.spinBox_pool.setValue(2)
		self.ui.checkBox_rote.setChecked(False)
		self.ui.comboBox_xAgain.setCurrentIndex(0)
		self.ui.spinBox_target.setValue(1)
		self.changeText()
		self.ui.radioButton_target.setChecked(True)
		self.ui.groupBox_extended.setChecked(False)
		self.ui.checkBox_rollsLimited.setChecked(True)

		self.dice = []
		for i in xrange(10):
			self.W10_x = QGraphicsSvgItem()
			self.W10_x.setSharedRenderer(self.svgRenderer)
			self.W10_x.setElementId("layer" + str(i))
			#self.W10_x.setVisible(False)
			# Ich lege diese Liste an, da ich auf die Liste in self.scene irgendwie nicht zugreifen kann.
			self.dice.append(self.W10_x)
			#self.scene.addItem(self.W10_x)


	def displayDice(self, value=None):
		"""
		@todo Der Würfel kann mehrmals in Folge das selbe Ergebnis anzeigen, was dazu führt, daß der Bildablauf zu stocken scheint.
		"""

		if (value == None):
			dieValue = Random.random(10)-1
		else:
			dieValue = value

		for item in self.scene.items():
			self.scene.removeItem(item)

		self.scene.addItem(self.dice[dieValue])
		self.view.setSceneRect(self.scene.itemsBoundingRect())
		self.view.fitInView(self.dice[dieValue])


	def changeDiceDisplay(self, number):
		"""
		Diese Funktion bestimmt, wieviele Würfel angezeigt werden.
		"""
		pass
		
		#if (self.ui.horizontalLayout_dice.count > 2):
			#pass
		
		#randomValue = Random.random(10)-1

		#for die in xrange(number):
			#self.__W10_scene = QGraphicsScene()
			#self.__W10_scene.addItem(self.dice[randomValue])
			
			#self.__W10_view = QGraphicsView()
			#self.__W10_view.setScene(self.__W10_scene)
			#self.__W10_view.setSceneRect(self.scene.itemsBoundingRect())
			#self.__W10_view.fitInView(self.dice[randomValue])
			#self.ui.horizontalLayout_dice.insertWidget(1, self.__W10_view)


	def aboutApp(self):
		"""
		Zeigt die Info-Nachricht an.
		"""

		self.appText = self.tr("""
			<h1>%1</h1>
			<h2>Version: %2</h2>
			<p>Copyright (C) 2011 by Victor von Rhein<br>
			EMail: [email protected]</p>
		""").arg(QCoreApplication.applicationName()).arg(QCoreApplication.applicationVersion())
		self.gnuText = self.tr("""
			<h2>GNU General Public License</h2>
			<p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation,  either version 3 of the License,  or (at your option) any later version.</p>
			<p>This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.</p>
			<p>You should have received a copy of the GNU General Public License along with this program.  If not,  see <a>http://www.gnu.org/licenses/</a>.</p>
		""")
		self.wodText = self.tr("""
			<h2>%1</h2>
			<p>%1,  %2,  the %3 and all referring terms and symbols are copyrighted by %4</p>
		""").arg("World of Darkness").arg("White Wolf").arg("White Wolf-Logo").arg("White Wolf Inc.")
		self.aboutText = self.appText + self.gnuText + self.wodText
		QMessageBox.about(self,  "About " + QCoreApplication.applicationName(),  self.aboutText )


	def roll(self):
		"""
		Der Wurf wird durchgeführt. Der tatsächliche Wurf wird aber von den Timern angestoßen.
		"""

		# Es wird ein rollender Würfel angezeigt.
		self.timerDice.start(DICEROLL_TIMER_INTERVAL)
		self.timerRoll.start(DICEROLL_TIMER_DELAY)


	def _executeRoll(self):
		"""
		Entscheidet vor dem eigentlichen Würfelwurf, ob ein normaler oder ein erweiterter Wurf notwendig ist und führt diesen aus.
		"""

		if self.ui.groupBox_extended.isChecked():
			#qDebug("Checked")
			self.extendedRoll.roll()
		else:
			#qDebug("Not Checked")
			self.instantRoll.roll()

		# Die Anzeige des rollenden Würfels wird angehalten
		self.timerDice.stop()
		self.timerRoll.stop()


	def calcDicePool(self, value):
		"""
		Berechnet die Größe des zur Verfügung stehenden Würfelpools, welcher von den Würfeln und den Modifikatoren abhängt.
		"""

		self.instantRoll.poolSize = value + self.ui.spinBox_modifier.value()
		self.extendedRoll.poolSize = self.instantRoll.poolSize
		self.extendedRoll.limit = value
		
		self.dicePoolChanged.emit(self.instantRoll.poolSize)


	def calcDicePoolMod(self, value):
		"""
		Berechnet wie schon calcDicePool() die Größe des Würfelvorrats, allerdings werden dieser Funktion andere Argumente übergeben.
		"""

		self.instantRoll.poolSize = value + self.ui.spinBox_pool.value()
		self.extendedRoll.poolSize = value + self.ui.spinBox_pool.value()


	def setHouserules(self, value):
		#qDebug("Test" + str(value))
		self.extendedRoll.isHouserules = value


	def setXAgainThreshold(self, value):
		"""
		Legt fest, bei welchem Ergebnis weitergewürfelt werden kann und wann dies überhaupt nicht der Fall sein sollte oder gar Erfolge abgezogen werden können.
		"""

		self.__threshold = 0
		if (value < 3):
			self.__threshold = 10 - value	# Index 0 entspricht 10 again, 1 entspricht 9 again etc.
		else:
			self.__threshold = 11	# Index 3 entspricht "no reroll"

		self.xAgainChanged.emit(self.__threshold)

		if (value > 3):
			self.cursed.emit(True)	# Kein reroll und 1er werden Abgezogen.
		else:
			self.cursed.emit(False)	# 1er werden nicht abgezogen.


	def setExtendedMode(self, sw):
		"""
		Legt den Modus fest, mit welchem der erweiterte Wurf durchgeführt wird. Entweder wird auf ein Ergebnishingewürfelt, oder nach einer bestimmten Anzahl würde die Anzahl der Erfolge gezählt.
		"""

		if (sw):
			self.extendedRoll.isResultInRolls = False
		else:
			self.extendedRoll.isResultInRolls = True


	def setResult(self, value):
		"""
		Schreibt das Ergebnis des Wurfs in die GUI. Dabei wird auch je nach Erfolgsqualität bei dem dargestellten Würfel eine andere Augenzahl gezeigt.
		"""

		self.ui.statusBar.showMessage(self.tr("Result of diceroll is displayed."))

		if (value == DieResult.dramaticFailure):
			self.ui.label_resultText.setText(self.tr("Dramatic Failure"));
			self.ui.label_result.setPixmap(QPixmap(":/icons/actions/cnrdelete-all1.png"));
			self.displayDice(1)
		elif (value == DieResult.failure):
			self.ui.label_resultText.setText(self.tr("Failure"));
			self.ui.label_result.setPixmap(QPixmap(":/icons/actions/fileclose.png"));
			self.displayDice(Random.random(2, 7))
		elif (value == DieResult.success):
			self.ui.label_resultText.setText(self.tr("Success"));
			self.ui.label_result.setPixmap(QPixmap(":/icons/actions/ok.png"));
			self.displayDice(Random.random(8, 9))
		else:
			self.ui.label_resultText.setText(self.tr("Exceptional Success"));
			self.ui.label_result.setPixmap(QPixmap(":/icons/actions/bookmark.png"));
			self.displayDice(0)


	def setResultRolls(self, value):
		"""
		Zeigt in der GUI an, wieviele Würfe nötig waren.
		"""

		if (self.ui.groupBox_extended.isChecked() and self.ui.radioButton_target.isChecked()):
			self.ui.lcdNumber_successes.display(value)


	def setResultSuccesses(self, value):
		"""
		Zeigt in der GUI an, wieviele Erfolge erzielt wurden.
		"""

		if (not self.ui.groupBox_extended.isChecked() or not self.ui.radioButton_target.isChecked()):
			self.ui.lcdNumber_successes.display(value)


	def changeText(self):
		"""
		Verändert den Text in der Statuszeile.
		"""

		if (self.ui.groupBox_extended.isChecked() and self.ui.radioButton_target.isChecked()):
			self.ui.label_successes.setText(self.tr("Number of rolls needed:"))
		else:
			self.ui.label_successes.setText(self.tr("Number of successes:"))


	def reset(self):
		"""
		Setzt das Programm auf einen definierten Startwert zurück.
		"""

		self.ui.label_result.setPixmap(QPixmap(":/icons/actions/fileclose.png"))
		self.ui.label_resultText.setText(self.tr("No result yet!"))
		self.ui.lcdNumber_successes.display(0)
		self.ui.statusBar.showMessage(self.tr("Press the Button to roll the dice!"))
Esempio n. 14
0
class OWSieveDiagram(OWWidget):
    name = "Sieve Diagram"
    description = "Visualize the observed and expected frequencies " \
                  "for a combination of values."
    icon = "icons/SieveDiagram.svg"
    priority = 200

    inputs = [("Data", Table, "set_data", Default),
              ("Features", AttributeList, "set_input_features")]
    outputs = [("Selection", Table)]

    graph_name = "canvas"

    want_control_area = False

    settingsHandler = DomainContextHandler()
    attrX = ContextSetting("", exclude_metas=False)
    attrY = ContextSetting("", exclude_metas=False)
    selection = ContextSetting(set())

    def __init__(self):
        # pylint: disable=missing-docstring
        super().__init__()

        self.data = self.discrete_data = None
        self.attrs = []
        self.input_features = None
        self.areas = []
        self.selection = set()

        self.attr_box = gui.hBox(self.mainArea)
        model = VariableListModel()
        model.wrap(self.attrs)
        combo_args = dict(widget=self.attr_box,
                          master=self,
                          contentsLength=12,
                          callback=self.update_attr,
                          sendSelectedValue=True,
                          valueType=str,
                          model=model)
        fixed_size = (QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.attrXCombo = gui.comboBox(value="attrX", **combo_args)
        gui.widgetLabel(self.attr_box, "\u2715", sizePolicy=fixed_size)
        self.attrYCombo = gui.comboBox(value="attrY", **combo_args)
        self.vizrank, self.vizrank_button = SieveRank.add_vizrank(
            self.attr_box, self, "Score Combinations", self.set_attr)
        self.vizrank_button.setSizePolicy(*fixed_size)

        self.canvas = QGraphicsScene()
        self.canvasView = ViewWithPress(self.canvas,
                                        self.mainArea,
                                        handler=self.reset_selection)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        box = gui.hBox(self.mainArea)
        box.layout().addWidget(self.graphButton)
        box.layout().addWidget(self.report_button)

    def sizeHint(self):
        return QSize(450, 550)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.update_graph()

    def showEvent(self, event):
        super().showEvent(event)
        self.update_graph()

    def set_data(self, data):
        """
        Discretize continuous attributes, and put all attributes and discrete
        metas into self.attrs, which is used as a model for combos.

        Select the first two attributes unless context overrides this.
        Method `resolve_shown_attributes` is called to use the attributes from
        the input, if it exists and matches the attributes in the data.

        Remove selection; again let the context override this.
        Initialize the vizrank dialog, but don't show it.

        Args:
            data (Table): input data
        """
        if isinstance(data, SqlTable) and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.closeContext()
        self.data = data
        self.areas = []
        self.selection = set()
        if self.data is None:
            self.attrs[:] = []
        else:
            if any(attr.is_continuous for attr in data.domain):
                discretizer = Discretize(method=EqualFreq(n=4),
                                         discretize_classes=True,
                                         discretize_metas=True)
                self.discrete_data = discretizer(data)
            else:
                self.discrete_data = self.data
            self.attrs[:] = [
                var for var in chain(self.discrete_data.domain, (
                    var for var in self.data.domain.metas if var.is_discrete))
            ]
        if self.attrs:
            self.attrX = self.attrs[0].name
            self.attrY = self.attrs[len(self.attrs) > 1].name
        else:
            self.attrX = self.attrY = None
            self.areas = []
            self.selection = set()
        self.openContext(self.data)
        self.resolve_shown_attributes()
        self.update_graph()
        self.update_selection()

        self.vizrank.initialize()
        self.vizrank_button.setEnabled(
            self.data is not None and len(self.data) > 1
            and len(self.data.domain.attributes) > 1)

    def set_attr(self, attr_x, attr_y):
        self.attrX, self.attrY = attr_x.name, attr_y.name
        self.update_attr()

    def update_attr(self):
        """Update the graph and selection."""
        self.selection = set()
        self.update_graph()
        self.update_selection()

    def set_input_features(self, attr_list):
        """
        Handler for the Features signal.

        The method stores the attributes and calls `resolve_shown_attributes`

        Args:
            attr_list (AttributeList): data from the signal
        """
        self.input_features = attr_list
        self.resolve_shown_attributes()
        self.update_selection()

    def resolve_shown_attributes(self):
        """
        Use the attributes from the input signal if the signal is present
        and at least two attributes appear in the domain. If there are
        multiple, use the first two. Combos are disabled if inputs are used.
        """
        self.warning()
        self.attr_box.setEnabled(True)
        if not self.input_features:  # None or empty
            return
        features = [f for f in self.input_features if f in self.attrs]
        if not features:
            self.warning(
                "Features from the input signal are not present in the data")
            return
        old_attrs = self.attrX, self.attrY
        self.attrX, self.attrY = [f.name for f in (features * 2)[:2]]
        self.attr_box.setEnabled(False)
        if (self.attrX, self.attrY) != old_attrs:
            self.selection = set()
            self.update_graph()

    def reset_selection(self):
        self.selection = set()
        self.update_selection()

    def select_area(self, area, event):
        """
        Add or remove the clicked area from the selection

        Args:
            area (QRect): the area that is clicked
            event (QEvent): event description
        """
        if event.button() != Qt.LeftButton:
            return
        index = self.areas.index(area)
        if event.modifiers() & Qt.ControlModifier:
            self.selection ^= {index}
        else:
            self.selection = {index}
        self.update_selection()

    def update_selection(self):
        """
        Update the graph (pen width) to show the current selection.
        Filter and output the data.
        """
        if self.areas is None or not self.selection:
            self.send("Selection", None)
            return

        filts = []
        for i, area in enumerate(self.areas):
            if i in self.selection:
                width = 4
                val_x, val_y = area.value_pair
                filts.append(
                    filter.Values([
                        filter.FilterDiscrete(self.attrX, [val_x]),
                        filter.FilterDiscrete(self.attrY, [val_y])
                    ]))
            else:
                width = 1
            pen = area.pen()
            pen.setWidth(width)
            area.setPen(pen)
        if len(filts) == 1:
            filts = filts[0]
        else:
            filts = filter.Values(filts, conjunction=False)
        selection = filts(self.discrete_data)
        if self.discrete_data is not self.data:
            idset = set(selection.ids)
            sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset]
            selection = self.data[sel_idx]
        self.send("Selection", selection)

    def update_graph(self):
        # Function uses weird names like r, g, b, but it does it with utmost
        # caution, hence
        # pylint: disable=invalid-name
        """Update the graph."""
        def text(txt, *args, **kwargs):
            return CanvasText(self.canvas,
                              "",
                              html_text=to_html(txt),
                              *args,
                              **kwargs)

        def width(txt):
            return text(txt, 0, 0, show=False).boundingRect().width()

        def fmt(val):
            return str(int(val)) if val % 1 == 0 else "{:.2f}".format(val)

        def show_pearson(rect, pearson, pen_width):
            """
            Color the given rectangle according to its corresponding
            standardized Pearson residual.

            Args:
                rect (QRect): the rectangle being drawn
                pearson (float): signed standardized pearson residual
                pen_width (int): pen width (bolder pen is used for selection)
            """
            r = rect.rect()
            x, y, w, h = r.x(), r.y(), r.width(), r.height()
            if w == 0 or h == 0:
                return

            r = b = 255
            if pearson > 0:
                r = g = max(255 - 20 * pearson, 55)
            elif pearson < 0:
                b = g = max(255 + 20 * pearson, 55)
            else:
                r = g = b = 224
            rect.setBrush(QBrush(QColor(r, g, b)))
            pen_color = QColor(255 * (r == 255), 255 * (g == 255),
                               255 * (b == 255))
            pen = QPen(pen_color, pen_width)
            rect.setPen(pen)
            if pearson > 0:
                pearson = min(pearson, 10)
                dist = 20 - 1.6 * pearson
            else:
                pearson = max(pearson, -10)
                dist = 20 - 8 * pearson
            pen.setWidth(1)

            def _offseted_line(ax, ay):
                r = QGraphicsLineItem(x + ax, y + ay, x + (ax or w),
                                      y + (ay or h))
                self.canvas.addItem(r)
                r.setPen(pen)

            ax = dist
            while ax < w:
                _offseted_line(ax, 0)
                ax += dist

            ay = dist
            while ay < h:
                _offseted_line(0, ay)
                ay += dist

        def make_tooltip():
            """Create the tooltip. The function uses local variables from
            the enclosing scope."""

            # pylint: disable=undefined-loop-variable
            def _oper(attr_name, txt):
                if self.data.domain[attr_name] is ddomain[attr_name]:
                    return "="
                return " " if txt[0] in "<≥" else " in "

            return ("<b>{attrX}{xeq}{xval_name}</b>: {obs_x}/{n} ({p_x:.0f} %)"
                    .format(attrX=to_html(attr_x),
                            xeq=_oper(attr_x, xval_name),
                            xval_name=to_html(xval_name),
                            obs_x=fmt(chi.probs_x[x] * n),
                            n=int(n),
                            p_x=100 * chi.probs_x[x]) + "<br/>" +
                    "<b>{attrY}{yeq}{yval_name}</b>: {obs_y}/{n} ({p_y:.0f} %)"
                    .format(attrY=to_html(attr_y),
                            yeq=_oper(attr_y, yval_name),
                            yval_name=to_html(yval_name),
                            obs_y=fmt(chi.probs_y[y] * n),
                            n=int(n),
                            p_y=100 * chi.probs_y[y]) + "<hr/>" +
                    """<b>combination of values: </b><br/>
                   &nbsp;&nbsp;&nbsp;expected {exp} ({p_exp:.0f} %)<br/>
                   &nbsp;&nbsp;&nbsp;observed {obs} ({p_obs:.0f} %)""".format(
                        exp=fmt(chi.expected[y, x]),
                        p_exp=100 * chi.expected[y, x] / n,
                        obs=fmt(chi.observed[y, x]),
                        p_obs=100 * chi.observed[y, x] / n))

        for item in self.canvas.items():
            self.canvas.removeItem(item)
        if self.data is None or len(self.data) == 0 or \
                self.attrX is None or self.attrY is None:
            return

        ddomain = self.discrete_data.domain
        attr_x, attr_y = self.attrX, self.attrY
        disc_x, disc_y = ddomain[attr_x], ddomain[attr_y]
        view = self.canvasView

        chi = ChiSqStats(self.discrete_data, attr_x, attr_y)
        n = chi.n
        max_ylabel_w = max((width(val) for val in disc_y.values), default=0)
        max_ylabel_w = min(max_ylabel_w, 200)
        x_off = width(attr_x) + max_ylabel_w
        y_off = 15
        square_size = min(view.width() - x_off - 35,
                          view.height() - y_off - 50)
        square_size = max(square_size, 10)
        self.canvasView.setSceneRect(0, 0, view.width(), view.height())

        curr_x = x_off
        max_xlabel_h = 0
        self.areas = []
        for x, (px, xval_name) in enumerate(zip(chi.probs_x, disc_x.values)):
            if px == 0:
                continue
            width = square_size * px

            curr_y = y_off
            for y in range(len(chi.probs_y) - 1, -1, -1):  # bottom-up order
                py = chi.probs_y[y]
                yval_name = disc_y.values[y]
                if py == 0:
                    continue
                height = square_size * py

                selected = len(self.areas) in self.selection
                rect = CanvasRectangle(self.canvas,
                                       curr_x + 2,
                                       curr_y + 2,
                                       width - 4,
                                       height - 4,
                                       z=-10,
                                       onclick=self.select_area)
                rect.value_pair = x, y
                self.areas.append(rect)
                show_pearson(rect, chi.residuals[y, x], 3 * selected)
                rect.setToolTip(make_tooltip())

                if x == 0:
                    text(yval_name, x_off, curr_y + height / 2,
                         Qt.AlignRight | Qt.AlignVCenter)
                curr_y += height

            xl = text(xval_name, curr_x + width / 2, y_off + square_size,
                      Qt.AlignHCenter | Qt.AlignTop)
            max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h)
            curr_x += width

        bottom = y_off + square_size + max_xlabel_h
        text(attr_y,
             0,
             y_off + square_size / 2,
             Qt.AlignLeft | Qt.AlignVCenter,
             bold=True,
             vertical=True)
        text(attr_x,
             x_off + square_size / 2,
             bottom,
             Qt.AlignHCenter | Qt.AlignTop,
             bold=True)
        xl = text("χ²={:.2f}, p={:.3f}".format(chi.chisq, chi.p), 0, bottom)
        # Assume similar height for both lines
        text("N = " + fmt(chi.n), 0, bottom - xl.boundingRect().height())

    def get_widget_name_extension(self):
        if self.data is not None:
            return "{} vs {}".format(self.attrX, self.attrY)

    def send_report(self):
        self.report_plot()
Esempio n. 15
0
class PaintArea(QGraphicsView):
    def __init__(self, parent):
        QGraphicsView.__init__(self)
        self.init(parent)
        self.initShape()
        self.initCall = 2
        self.minimumWidth = 550
        self.setEnabled(False)

    def init(self, parent):
        self.timeline = parent
        self.pixmap = None
        self.image = None

    def initShape(self):
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setAlignment(Qt.AlignLeft)
        self.clicStart = None
        self.selectionRect = None

    def resizeEvent(self, sizEvent):
        if self.selectionRect and self.scene:
          self.scene.removeItem(self.selectionRect)
          self.selectionRect = None
          self.clicStart = None

        self.width = sizEvent.size().width()
        self.height = sizEvent.size().height()

        if self.initCall > 0:
          self.timeline.options.setMaximumWidth(self.timeline.options.minimumSizeHint().width())
          self.initCall -= 1

        if self.width < self.minimumWidth:
          self.timeline.setStateInfo('Unable to draw - Not enought width')
        else:
          self.timeline.workerThread.render()
          

    def mousePressEvent(self, mouseEvent):
      self.clicStart = mouseEvent.pos()
      if self.clicStart.x() < self.timeline.draw.yLeftMargin - 1:
        self.clicStart.setX(self.timeline.draw.yLeftMargin - 1)
      if self.clicStart.x() > self.timeline.ploter.width - self.timeline.m + 1:
        self.clicStart.setX(self.timeline.ploter.width - self.timeline.m + 1)
        
      if self.selectionRect:
        for item in self.scene.items():
          if str(type(item)) == "<class 'PyQt4.QtGui.QGraphicsRectItem'>":
            self.scene.removeItem(item)
        self.selectionRect = None
        self.timeline.options.zoomButton.setEnabled(False)
        self.timeline.options.exportButton.setEnabled(False)
        self.timeline.options.selectedNodes.setText('Nothing selected')
        if self.timeline.selDateMin:
          self.timeline.options.selStartTime.setText('From ' + str(self.timeline.fromUSec(self.timeline.baseDateMin).strftime('%d.%m.%Y %H:%M:%S')))
          self.timeline.options.selEndTime.setText('To ' + str(self.timeline.fromUSec(self.timeline.baseDateMax).strftime('%d.%m.%Y %H:%M:%S')))
        else:
          self.timeline.options.selStartTime.setText('No selection start time')
          self.timeline.options.selEndTime.setText('No selection end time')
        self.timeline.options.selectedNodes.setText('Nothing selected')
 

    def mouseMoveEvent(self, dragMoveEvent):
      if self.clicStart:
        if self.clicStart.x() < dragMoveEvent.x():
          x = self.clicStart.x()
          w = dragMoveEvent.x() - self.clicStart.x()
        else:
          x = dragMoveEvent.x()
          w = self.clicStart.x() - dragMoveEvent.x()

# Limit rectangle to selectable area
        if x < self.timeline.draw.yLeftMargin - 1:
          x = self.timeline.draw.yLeftMargin - 1
          w = self.clicStart.x() - x
        if x > self.timeline.ploter.width - self.timeline.m + 1:
          x = self.timeline.ploter.width - self.timeline.m + 1
          w = 0
        if x + w > self.timeline.ploter.width - self.timeline.m + 1:
          w = ((self.timeline.ploter.width - self.timeline.m + 1) - x)
        
        y = (self.timeline.m / 3) - 1
        h = self.height - self.timeline.m - self.timeline.m / 3 + 2
        if self.selectionRect and self.scene:
          self.scene.removeItem(self.selectionRect)
        self.selectionRect = self.scene.addRect(QRectF(x, y, w, h), QPen(Qt.DashDotDotLine))

    def mouseReleaseEvent(self, mouseEvent):
      if self.selectionRect:
        if self.clicStart.x() > mouseEvent.x():
          x1 = mouseEvent.x()
          x2 = self.clicStart.x()
        else:
          x1 = self.clicStart.x()
          x2 = mouseEvent.x()
        self.timeline.nodesInRange(x1, x2)
        start = self.timeline.draw.findXTime(x1)
        if start:
          self.timeline.options.selStartTime.setText('From ' + str(start.strftime('%d.%m.%Y %H:%M:%S')))
        end = self.timeline.draw.findXTime(x2)
        if end:
          self.timeline.options.selEndTime.setText('To ' + str(end.strftime('%d.%m.%Y %H:%M:%S')))
Esempio n. 16
0
 def items(self, *args, **kwargs):
     items = QGraphicsScene.items(self, *args, **kwargs)
     return map(toGraphicsObjectIfPossible, items)
Esempio n. 17
0
class ImagesPreviewer(foundations.ui.common.QWidgetFactory(uiFile=UI_FILE)):
    """
	| This class provides the Application images previewer.
	| It defines methods to navigate through the list of given images ( List of images paths ),
		zoom in / out and fit the displayed image, etc...
	"""
    def __init__(self, parent, paths=None, *args, **kwargs):
        """
		This method initializes the class.

		:param parent: Object parent. ( QObject )
		:param paths: Images paths. ( Tuple / List )
		:param \*args: Arguments. ( \* )
		:param \*\*kwargs: Keywords arguments. ( \*\* )
		"""

        LOGGER.debug("> Initializing '{0}()' class.".format(
            self.__class__.__name__))

        super(ImagesPreviewer, self).__init__(parent, *args, **kwargs)

        # --- Setting class attributes. ---
        self.__container = parent
        self.__paths = None
        self.paths = paths

        self.__uiResourcesDirectory = "resources"
        self.__uiResourcesDirectory = os.path.join(os.path.dirname(__file__),
                                                   self.__uiResourcesDirectory)
        self.__uiPreviousImage = "Previous.png"
        self.__uiNextImage = "Next.png"
        self.__uiZoomOutImage = "Zoom_Out.png"
        self.__uiZoomInImage = "Zoom_In.png"

        # Ensure the ui object is destroyed on close to avoid memory leaks.
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.__graphicsSceneBackgroundColor = QColor(32, 32, 32)
        self.__minimumZoomFactor = 0.05
        self.__maximumZoomFactor = 25
        self.__displayGraphicsItemMargin = 32
        self.__graphicsSceneWidth = QApplication.desktop().screenGeometry(
            QApplication.desktop().primaryScreen()).width() * (
                1 / self.__minimumZoomFactor * 1.75)
        self.__graphicsSceneHeight = QApplication.desktop().screenGeometry(
            QApplication.desktop().primaryScreen()).height() * (
                1 / self.__minimumZoomFactor * 1.75)
        self.__wheelZoomFactor = 350.0
        self.__keyZoomFactor = 1.20

        self.__graphicsView = None
        self.__graphicsScene = None
        self.__displayGraphicsItem = None

        ImagesPreviewer.__initializeUi(self)

        self.loadImage()

    #******************************************************************************************************************
    #***	Attributes properties.
    #******************************************************************************************************************
    @property
    def container(self):
        """
		This method is the property for **self.__container** attribute.

		:return: self.__container. ( QObject )
		"""

        return self.__container

    @container.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def container(self, value):
        """
		This method is the setter method for **self.__container** attribute.

		:param value: Attribute value. ( QObject )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "container"))

    @container.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def container(self):
        """
		This method is the deleter method for **self.__container** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "container"))

    @property
    def paths(self):
        """
		This method is the property for **self.__paths** attribute.

		:return: self.__paths. ( Tuple / List )
		"""

        return self.__paths

    @paths.setter
    @foundations.exceptions.handleExceptions(AssertionError)
    def paths(self, value):
        """
		This method is the setter method for **self.__paths** attribute.

		:param value: Attribute value. ( Tuple / List )
		"""

        if value is not None:
            assert type(value) in (
                tuple, list
            ), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
                "paths", value)
            for element in value:
                assert type(
                    element
                ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
                    "paths", element)
        self.__paths = value

    @paths.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def paths(self):
        """
		This method is the deleter method for **self.__paths** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "paths"))

    @property
    def uiResourcesDirectory(self):
        """
		This method is the property for **self.__uiResourcesDirectory** attribute.

		:return: self.__uiResourcesDirectory. ( String )
		"""

        return self.__uiResourcesDirectory

    @uiResourcesDirectory.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiResourcesDirectory(self, value):
        """
		This method is the setter method for **self.__uiResourcesDirectory** attribute.

		:param value: Attribute value. ( String )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "uiResourcesDirectory"))

    @uiResourcesDirectory.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiResourcesDirectory(self):
        """
		This method is the deleter method for **self.__uiResourcesDirectory** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "uiResourcesDirectory"))

    @property
    def uiPreviousImage(self):
        """
		This method is the property for **self.__uiPreviousImage** attribute.

		:return: self.__uiPreviousImage. ( String )
		"""

        return self.__uiPreviousImage

    @uiPreviousImage.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiPreviousImage(self, value):
        """
		This method is the setter method for **self.__uiPreviousImage** attribute.

		:param value: Attribute value. ( String )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "uiPreviousImage"))

    @uiPreviousImage.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiPreviousImage(self):
        """
		This method is the deleter method for **self.__uiPreviousImage** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "uiPreviousImage"))

    @property
    def uiNextImage(self):
        """
		This method is the property for **self.__uiNextImage** attribute.

		:return: self.__uiNextImage. ( String )
		"""

        return self.__uiNextImage

    @uiNextImage.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiNextImage(self, value):
        """
		This method is the setter method for **self.__uiNextImage** attribute.

		:param value: Attribute value. ( String )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "uiNextImage"))

    @uiNextImage.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiNextImage(self):
        """
		This method is the deleter method for **self.__uiNextImage** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "uiNextImage"))

    @property
    def uiZoomOutImage(self):
        """
		This method is the property for **self.__uiZoomOutImage** attribute.

		:return: self.__uiZoomOutImage. ( String )
		"""

        return self.__uiZoomOutImage

    @uiZoomOutImage.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiZoomOutImage(self, value):
        """
		This method is the setter method for **self.__uiZoomOutImage** attribute.

		:param value: Attribute value. ( String )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "uiZoomOutImage"))

    @uiZoomOutImage.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiZoomOutImage(self):
        """
		This method is the deleter method for **self.__uiZoomOutImage** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "uiZoomOutImage"))

    @property
    def uiZoomInImage(self):
        """
		This method is the property for **self.__uiZoomInImage** attribute.

		:return: self.__uiZoomInImage. ( String )
		"""

        return self.__uiZoomInImage

    @uiZoomInImage.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiZoomInImage(self, value):
        """
		This method is the setter method for **self.__uiZoomInImage** attribute.

		:param value: Attribute value. ( String )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "uiZoomInImage"))

    @uiZoomInImage.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def uiZoomInImage(self):
        """
		This method is the deleter method for **self.__uiZoomInImage** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "uiZoomInImage"))

    @property
    def graphicsSceneBackgroundColor(self):
        """
		This method is the property for **self.__graphicsSceneBackgroundColor** attribute.

		:return: self.__graphicsSceneBackgroundColor. ( QColors )
		"""

        return self.__graphicsSceneBackgroundColor

    @graphicsSceneBackgroundColor.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsSceneBackgroundColor(self, value):
        """
		This method is the setter method for **self.__graphicsSceneBackgroundColor** attribute.

		:param value: Attribute value. ( QColors )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "graphicsSceneBackgroundColor"))

    @graphicsSceneBackgroundColor.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsSceneBackgroundColor(self):
        """
		This method is the deleter method for **self.__graphicsSceneBackgroundColor** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "graphicsSceneBackgroundColor"))

    @property
    def graphicsSceneWidth(self):
        """
		This method is the property for **self.__graphicsSceneWidth** attribute.

		:return: self.__graphicsSceneWidth. ( Integer )
		"""

        return self.__graphicsSceneWidth

    @graphicsSceneWidth.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsSceneWidth(self, value):
        """
		This method is the setter method for **self.__graphicsSceneWidth** attribute.

		:param value: Attribute value. ( Integer )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "graphicsSceneWidth"))

    @graphicsSceneWidth.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsSceneWidth(self):
        """
		This method is the deleter method for **self.__graphicsSceneWidth** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "graphicsSceneWidth"))

    @property
    def graphicsSceneHeight(self):
        """
		This method is the property for **self.__graphicsSceneHeight** attribute.

		:return: self.__graphicsSceneHeight. ( Object )
		"""

        return self.__graphicsSceneHeight

    @graphicsSceneHeight.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsSceneHeight(self, value):
        """
		This method is the setter method for **self.__graphicsSceneHeight** attribute.

		:param value: Attribute value. ( Object )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "graphicsSceneHeight"))

    @graphicsSceneHeight.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsSceneHeight(self):
        """
		This method is the deleter method for **self.__graphicsSceneHeight** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "graphicsSceneHeight"))

    @property
    def minimumZoomFactor(self):
        """
		This method is the property for **self.__minimumZoomFactor** attribute.

		:return: self.__minimumZoomFactor. ( Float )
		"""

        return self.__minimumZoomFactor

    @minimumZoomFactor.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def minimumZoomFactor(self, value):
        """
		This method is the setter method for **self.__minimumZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "minimumZoomFactor"))

    @minimumZoomFactor.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def minimumZoomFactor(self):
        """
		This method is the deleter method for **self.__minimumZoomFactor** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "minimumZoomFactor"))

    @property
    def maximumZoomFactor(self):
        """
		This method is the property for **self.__maximumZoomFactor** attribute.

		:return: self.__maximumZoomFactor. ( Float )
		"""

        return self.__maximumZoomFactor

    @maximumZoomFactor.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def maximumZoomFactor(self, value):
        """
		This method is the setter method for **self.__maximumZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "maximumZoomFactor"))

    @maximumZoomFactor.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def maximumZoomFactor(self):
        """
		This method is the deleter method for **self.__maximumZoomFactor** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "maximumZoomFactor"))

    @property
    def wheelZoomFactor(self):
        """
		This method is the property for **self.__wheelZoomFactor** attribute.

		:return: self.__wheelZoomFactor. ( Float )
		"""

        return self.__wheelZoomFactor

    @wheelZoomFactor.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def wheelZoomFactor(self, value):
        """
		This method is the setter method for **self.__wheelZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "wheelZoomFactor"))

    @wheelZoomFactor.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def wheelZoomFactor(self):
        """
		This method is the deleter method for **self.__wheelZoomFactor** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "wheelZoomFactor"))

    @property
    def keyZoomFactor(self):
        """
		This method is the property for **self.__keyZoomFactor** attribute.

		:return: self.__keyZoomFactor. ( Float )
		"""

        return self.__keyZoomFactor

    @keyZoomFactor.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def keyZoomFactor(self, value):
        """
		This method is the setter method for **self.__keyZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "keyZoomFactor"))

    @keyZoomFactor.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def keyZoomFactor(self):
        """
		This method is the deleter method for **self.__keyZoomFactor** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "keyZoomFactor"))

    @property
    def graphicsView(self):
        """
		This method is the property for **self.__graphicsView** attribute.

		:return: self.__graphicsView. ( QGraphicsView )
		"""

        return self.__graphicsView

    @graphicsView.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsView(self, value):
        """
		This method is the setter method for **self.__graphicsView** attribute.

		:param value: Attribute value. ( QGraphicsView )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "graphicsView"))

    @graphicsView.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsView(self):
        """
		This method is the deleter method for **self.__graphicsView** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "graphicsView"))

    @property
    def graphicsScene(self):
        """
		This method is the property for **self.__graphicsScene** attribute.

		:return: self.__graphicsScene. ( QGraphicsScene )
		"""

        return self.__graphicsScene

    @graphicsScene.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsScene(self, value):
        """
		This method is the setter method for **self.__graphicsScene** attribute.

		:param value: Attribute value. ( QGraphicsScene )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "graphicsScene"))

    @graphicsScene.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def graphicsScene(self):
        """
		This method is the deleter method for **self.__graphicsScene** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "graphicsScene"))

    @property
    def displayGraphicsItem(self):
        """
		This method is the property for **self.__displayGraphicsItem** attribute.

		:return: self.__displayGraphicsItem. ( QGraphicsItem )
		"""

        return self.__displayGraphicsItem

    @displayGraphicsItem.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def displayGraphicsItem(self, value):
        """
		This method is the setter method for **self.__displayGraphicsItem** attribute.

		:param value: Attribute value. ( QGraphicsItem )
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "displayGraphicsItem"))

    @displayGraphicsItem.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def displayGraphicsItem(self):
        """
		This method is the deleter method for **self.__displayGraphicsItem** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "displayGraphicsItem"))

    #******************************************************************************************************************
    #***	Class methods.
    #******************************************************************************************************************
    def show(self):
        """
		This method reimplements the :meth:`QWidget.show` method.
		"""

        super(ImagesPreviewer, self).show()

        foundations.ui.common.centerWidgetOnScreen(self)

    def closeEvent(self, event):
        """
		This method reimplements the :meth:`QWidget.closeEvent` method.

		:param event: QEvent ( QEvent )
		"""

        LOGGER.debug(
            "> Removing '{0}' from Images Previewers list.".format(self))
        self.__container.imagesPreviewers.remove(self)

        event.accept()

    def wheelEvent(self, event):
        """
		This method reimplements the :meth:`QWidget.wheelEvent` method.

		:param event: QEvent ( QEvent )
		"""

        self.scaleView(pow(1.5, event.delta() / self.__wheelZoomFactor))

    def keyPressEvent(self, event):
        """
		This method reimplements the :meth:`QWidget.keyPressEvent` method.

		:param event: QEvent ( QEvent )
		"""

        key = event.key()
        if key == Qt.Key_Plus:
            self.scaleView(self.__keyZoomFactor)
        elif key == Qt.Key_Minus:
            self.scaleView(1 / self.__keyZoomFactor)
        else:
            super(ImagesPreviewer, self).keyPressEvent(event)

    def __initializeUi(self):
        """
		This method initializes the Widget ui.
		"""

        LOGGER.debug("> Initializing '{0}' ui.".format(
            self.__class__.__name__))

        self.Previous_Image_pushButton.setIcon(
            QIcon(
                os.path.join(self.__uiResourcesDirectory,
                             self.__uiPreviousImage)))
        self.Next_Image_pushButton.setIcon(
            QIcon(os.path.join(self.__uiResourcesDirectory,
                               self.__uiNextImage)))
        self.Zoom_In_pushButton.setIcon(
            QIcon(
                os.path.join(self.__uiResourcesDirectory,
                             self.__uiZoomInImage)))
        self.Zoom_Out_pushButton.setIcon(
            QIcon(
                os.path.join(self.__uiResourcesDirectory,
                             self.__uiZoomOutImage)))
        len(self.__paths) <= 1 and self.Navigation_frame.hide()

        LOGGER.debug("> Initializing graphics View.")
        self.__graphicsView = QGraphicsView()
        self.__graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.__graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.__graphicsView.setTransformationAnchor(
            QGraphicsView.AnchorUnderMouse)
        self.__graphicsView.setDragMode(QGraphicsView.ScrollHandDrag)
        # Reimplementing QGraphicsView wheelEvent method.
        self.__graphicsView.wheelEvent = self.wheelEvent

        LOGGER.debug("> Initializing graphics scene.")
        self.__graphicsScene = QGraphicsScene(self.__graphicsView)
        self.__graphicsScene.setItemIndexMethod(QGraphicsScene.NoIndex)
        self.__graphicsScene.setSceneRect(
            -(float(self.__graphicsSceneWidth)) / 2,
            -(float(self.__graphicsSceneHeight)) / 2,
            float(self.__graphicsSceneWidth),
            float(self.__graphicsSceneHeight))

        self.__graphicsView.setScene(self.__graphicsScene)
        self.__graphicsView.setBackgroundBrush(
            QBrush(self.__graphicsSceneBackgroundColor))

        self.Images_Previewer_frame_gridLayout.addWidget(self.__graphicsView)

        # Signals / Slots.
        self.__container.engine.imagesCaches.QImage.contentAdded.connect(
            self.__engine_imagesCaches_QImage__contentAdded)
        self.Previous_Image_pushButton.clicked.connect(
            self.__Previous_Image_pushButton__clicked)
        self.Next_Image_pushButton.clicked.connect(
            self.__Next_Image_pushButton__clicked)
        self.Zoom_Out_pushButton.clicked.connect(
            self.__Zoom_Out_pushButton__clicked)
        self.Zoom_In_pushButton.clicked.connect(
            self.__Zoom_In_pushButton__clicked)
        self.Zoom_Fit_pushButton.clicked.connect(
            self.__Zoom_Fit_pushButton__clicked)

    def __Images_Informations_label_setUi(self):
        """
		This method sets the **Images_Informations_label** Widget ui.
		"""

        if not self.__displayGraphicsItem:
            return

        image = self.__displayGraphicsItem.image
        self.Images_Informations_label.setText(
            "{0} - {1}x{2} px - {3} bit".format(
                os.path.basename(image.data.path), image.data.width,
                image.data.height, image.data.bpp / 4))

    def __engine_imagesCaches_QImage__contentAdded(self, content):
        """
		This method is triggered by the Application **QImage** images cache when content has been added.

		:param content: Cache added content. ( List )
		"""

        if not self.__paths:
            return

        path = foundations.common.getFirstItem(content)
        if not path in self.__paths:
            return

        image = self.__container.engine.imagesCaches.QImage.getContent(path)
        self.__setDisplayGraphicsItem(image)

    def __Previous_Image_pushButton__clicked(self, checked):
        """
		This method is triggered when **Previous_Image_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

        self.loopThroughImages(True)

    def __Next_Image_pushButton__clicked(self, checked):
        """
		This method is triggered when **Next_Image_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

        self.loopThroughImages()

    def __Zoom_In_pushButton__clicked(self, checked):
        """
		This method is triggered when **Zoom_In_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

        self.scaleView(self.__keyZoomFactor)

    def __Zoom_Out_pushButton__clicked(self, checked):
        """
		This method is triggered when **Zoom_Out_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

        self.scaleView(1 / self.__keyZoomFactor)

    def __Zoom_Fit_pushButton__clicked(self, checked):
        """
		This method is triggered when **Zoom_Fit_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

        self.fitImage()

    def __clearGraphicsScene(self):
        """
		This method clears the View.
		"""

        for graphicsItem in self.__graphicsScene.items():
            self.__graphicsScene.removeItem(graphicsItem)

    def __setDisplayGraphicsItem(self, image):
        """
		This method sets the View using given image.

		:param image: Image to display. ( Qimage )
		"""

        self.__clearGraphicsScene()

        LOGGER.debug("> Initializing graphics item.")
        self.__displayGraphicsItem = Image_QGraphicsItem(image=image)
        self.__graphicsScene.addItem(self.__displayGraphicsItem)

        self.__Images_Informations_label_setUi()

    def loadImage(self, index=0):
        """
		This method loads the display image in the View.

		:param index: Index to load. ( Integer )
		:return: Method success. ( Boolean )
		"""

        if not self.__paths:
            return False

        image = sibl_gui.ui.common.getImage(self.__paths[index])
        self.__setDisplayGraphicsItem(image)

        return True

    def scaleView(self, scaleFactor):
        """
		This method scales the Previewer view.

		:param scaleFactor: Float ( Float )
		:return: Method success. ( Boolean )
		"""

        graphicsView = self.findChild(QGraphicsView)
        factor = graphicsView.matrix().scale(scaleFactor, scaleFactor).mapRect(
            QRectF(0, 0, 1, 1)).width()
        if factor < self.__minimumZoomFactor or factor > self.__maximumZoomFactor:
            return False

        graphicsView.scale(scaleFactor, scaleFactor)
        return True

    def fitWindow(self):
        """
		This method fits the View window.
		
		:return: Method success. ( Boolean )
		"""

        if not self.__displayGraphicsItem:
            return False

        desktopWidth = QApplication.desktop().screenGeometry(
            QApplication.desktop().primaryScreen()).width()
        desktopHeight = QApplication.desktop().screenGeometry(
            QApplication.desktop().primaryScreen()).height()
        width = min(desktopWidth * 0.80, self.__displayGraphicsItem.width)
        height = min(desktopHeight * 0.80, self.__displayGraphicsItem.height)
        self.resize(width, height)

        foundations.ui.common.centerWidgetOnScreen(self)

        return True

    def fitImage(self):
        """
		This method fits the image to the View.
		
		:return: Method success. ( Boolean )
		"""

        if not self.__displayGraphicsItem:
            return False

        self.__graphicsView.fitInView(
            QRectF(
                -(self.__displayGraphicsItem.width / 2) -
                (self.__displayGraphicsItemMargin / 2),
                -(self.__displayGraphicsItem.height / 2) -
                (self.__displayGraphicsItemMargin / 2),
                self.__displayGraphicsItem.width +
                self.__displayGraphicsItemMargin,
                self.__displayGraphicsItem.height +
                self.__displayGraphicsItemMargin), Qt.KeepAspectRatio)
        return True

    def loopThroughImages(self, backward=False):
        """
		This method loops through View images.

		:param backward: Looping backward. ( Boolean )
		:return: Method success. ( Boolean )
		"""

        index = self.__paths.index(self.__displayGraphicsItem.image.data.path)
        index += not backward and 1 or -1
        if index < 0:
            index = len(self.__paths) - 1
        elif index > len(self.__paths) - 1:
            index = 0
        self.loadImage(index)
        return True
Esempio n. 18
0
class OWSieveDiagram(OWWidget):
    name = "Sieve Diagram"
    description = "A two-way contingency table providing information on the " \
                  "relation between the observed and expected frequencies " \
                  "of a combination of feature values under the assumption of independence."
    icon = "icons/SieveDiagram.svg"
    priority = 4200

    inputs = [("Data", Table, "set_data", Default),
              ("Features", AttributeList, "set_input_features")]
    outputs = [("Selection", Table)]

    graph_name = "canvas"

    want_control_area = False

    settingsHandler = DomainContextHandler()
    attrX = ContextSetting("")
    attrY = ContextSetting("")
    selection = ContextSetting(set())

    def __init__(self):
        super().__init__()

        self.data = None
        self.input_features = None
        self.attrs = []

        self.attr_box = gui.hBox(self.mainArea)
        model = VariableListModel()
        model.wrap(self.attrs)
        self.attrXCombo = gui.comboBox(
            self.attr_box, self, value="attrX", contentsLength=12,
            callback=self.change_attr, sendSelectedValue=True, valueType=str)
        self.attrXCombo.setModel(model)
        gui.widgetLabel(self.attr_box, "\u2715").\
            setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.attrYCombo = gui.comboBox(
            self.attr_box, self, value="attrY", contentsLength=12,
            callback=self.change_attr, sendSelectedValue=True, valueType=str)
        self.attrYCombo.setModel(model)

        self.canvas = QGraphicsScene()
        self.canvasView = ViewWithPress(self.canvas, self.mainArea,
                                         handler=self.reset_selection)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        box = gui.hBox(self.mainArea)
        box.layout().addWidget(self.graphButton)
        box.layout().addWidget(self.report_button)

    def sizeHint(self):
        return QSize(450, 550)

    def set_data(self, data):
        if type(data) == SqlTable and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.closeContext()
        self.data = data
        self.areas = []
        if self.data is None:
            self.attrs[:] = []
        else:
            self.attrs[:] = [
                var for var in chain(self.data.domain,
                                     self.data.domain.metas)
                if var.is_discrete
            ]
        if self.attrs:
            self.attrX = self.attrs[0].name
            self.attrY = self.attrs[len(self.attrs) > 1].name
        else:
            self.attrX = self.attrY = None
        self.openContext(self.data)

        self.information(0, "")
        if data and any(attr.is_continuous for attr in data.domain):
            self.information(0, "Data contains continuous variables. "
                                "Discretize the data to use them.")
        self.resolve_shown_attributes()
        self.update_selection()

    def change_attr(self):
        self.selection = set()
        self.updateGraph()
        self.update_selection()

    def set_input_features(self, attrList):
        self.input_features = attrList
        self.resolve_shown_attributes()
        self.update_selection()

    def resolve_shown_attributes(self):
        self.warning(1)
        self.attr_box.setEnabled(True)
        if self.input_features:  # non-None and non-empty!
            features = [f for f in self.input_features if f in self.attrs]
            if not features:
                self.warning(1, "Features from the input signal "
                                "are not present in the data")
            else:
                old_attrs = self.attrX, self.attrY
                self.attrX, self.attrY = [f.name for f in (features * 2)[:2]]
                self.attr_box.setEnabled(False)
                if (self.attrX, self.attrY) != old_attrs:
                    self.selection = set()
        # else: do nothing; keep current features, even if input with the
        # features just changed to None
        self.updateGraph()

    def resizeEvent(self, e):
        OWWidget.resizeEvent(self,e)
        self.updateGraph()

    def showEvent(self, ev):
        OWWidget.showEvent(self, ev)
        self.updateGraph()

    def reset_selection(self):
        self.selection = set()
        self.update_selection()

    def select_area(self, area, ev):
        if ev.button() != Qt.LeftButton:
            return
        index = self.areas.index(area)
        if ev.modifiers() & Qt.ControlModifier:
            self.selection ^= {index}
        else:
            self.selection = {index}
        self.update_selection()

    def update_selection(self):
        if self.areas is None or not self.selection:
            self.send("Selection", None)
            return

        filters = []
        for i, area in enumerate(self.areas):
            if i in self.selection:
                width = 4
                val_x, val_y = area.value_pair
                filters.append(
                    filter.Values([
                        filter.FilterDiscrete(self.attrX, [val_x]),
                        filter.FilterDiscrete(self.attrY, [val_y])
                    ]))
            else:
                width = 1
            pen = area.pen()
            pen.setWidth(width)
            area.setPen(pen)
        if len(filters) == 1:
            filters = filters[0]
        else:
            filters = filter.Values(filters, conjunction=False)
        self.send("Selection", filters(self.data))

    # -----------------------------------------------------------------------
    # Everything from here on is ancient and has been changed only according
    # to what has been changed above. Some clean-up may be in order some day
    #
    def updateGraph(self, *args):
        for item in self.canvas.items():
            self.canvas.removeItem(item)
        if self.data is None or len(self.data) == 0 or \
                self.attrX is None or self.attrY is None:
            return
        data = self.data[:, [self.attrX, self.attrY]]
        valsX = []
        valsY = []
        contX = get_contingency(data, self.attrX, self.attrX)
        contY = get_contingency(data, self.attrY, self.attrY)
        # compute contingency of x and y attributes
        for entry in contX:
            sum_ = 0
            try:
                for val in entry: sum_ += val
            except: pass
            valsX.append(sum_)

        for entry in contY:
            sum_ = 0
            try:
                for val in entry: sum_ += val
            except: pass
            valsY.append(sum_)

        contXY, _ = get_conditional_distribution(
            data, [data.domain[self.attrX], data.domain[self.attrY]])
        # compute probabilities
        probs = {}
        for i in range(len(valsX)):
            valx = valsX[i]
            for j in range(len(valsY)):
                valy = valsY[j]
                try:
                    actualProb = contXY['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                    # for val in contXY['%s-%s' %(i, j)]: actualProb += val
                except:
                    actualProb = 0
                probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])] = ((data.domain[self.attrX].values[i], valx), (data.domain[self.attrY].values[j], valy), actualProb, len(data))

        #get text width of Y labels
        max_ylabel_w = 0
        for j in range(len(valsY)):
            xl = CanvasText(self.canvas, "", 0, 0, html_text= getHtmlCompatibleString(data.domain[self.attrY].values[j]), show=False)
            max_ylabel_w = max(int(xl.boundingRect().width()), max_ylabel_w)
        max_ylabel_w = min(max_ylabel_w, 200) #upper limit for label widths
        # get text width of Y attribute name
        text = CanvasText(self.canvas, data.domain[self.attrY].name, x  = 0, y = 0, bold = 1, show = 0, vertical=True)
        xOff = int(text.boundingRect().height() + max_ylabel_w)
        yOff = 55
        sqareSize = min(self.canvasView.width() - xOff - 35, self.canvasView.height() - yOff - 50)
        sqareSize = max(sqareSize, 10)
        self.canvasView.setSceneRect(0, 0, self.canvasView.width(), self.canvasView.height())

        # print graph name
        name  = "<b>P(%s, %s) &#8800; P(%s)&times;P(%s)</b>" %(self.attrX, self.attrY, self.attrX, self.attrY)
        CanvasText(self.canvas, "", xOff + sqareSize / 2, 20, Qt.AlignCenter, html_text= name)
        CanvasText(self.canvas, "N = " + str(len(data)), xOff + sqareSize / 2, 38, Qt.AlignCenter, bold = 0)

        ######################
        # compute chi-square
        chisquare = 0.0
        for i in range(len(valsX)):
            for j in range(len(valsY)):
                ((xAttr, xVal), (yAttr, yVal), actual, sum_) = probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                expected = float(xVal*yVal)/float(sum_)
                if expected == 0: continue
                pearson2 = (actual - expected)*(actual - expected) / expected
                chisquare += pearson2

        ######################
        # draw rectangles
        currX = xOff
        max_xlabel_h = 0
        normX, normY = sum(valsX), sum(valsY)
        self.areas = []
        for i in range(len(valsX)):
            if valsX[i] == 0: continue
            currY = yOff
            width = int(float(sqareSize * valsX[i])/float(normX))

            for j in range(len(valsY)-1, -1, -1):   # this way we sort y values correctly
                ((xAttr, xVal), (yAttr, yVal), actual, sum_) = probs['%s-%s' %(data.domain[self.attrX].values[i], data.domain[self.attrY].values[j])]
                if valsY[j] == 0: continue
                height = int(float(sqareSize * valsY[j])/float(normY))

                # create rectangle
                selected = len(self.areas) in self.selection
                rect = CanvasRectangle(
                    self.canvas, currX+2, currY+2, width-4, height-4, z = -10,
                    onclick=self.select_area)
                rect.value_pair = i, j
                self.areas.append(rect)
                self.addRectIndependencePearson(rect, currX+2, currY+2, width-4, height-4, (xAttr, xVal), (yAttr, yVal), actual, sum_,
                    width=1 + 3 * selected,  # Ugly! This is needed since
                    # resize redraws the graph! When this is handled by resizing
                    # just the viewer, update_selection will take care of this
                    )

                expected = float(xVal*yVal)/float(sum_)
                pearson = (actual - expected) / sqrt(expected)
                tooltipText = """<b>X Attribute: %s</b><br>Value: <b>%s</b><br>Number of instances (p(x)): <b>%d (%.2f%%)</b><hr>
                                <b>Y Attribute: %s</b><br>Value: <b>%s</b><br>Number of instances (p(y)): <b>%d (%.2f%%)</b><hr>
                                <b>Number Of Instances (Probabilities):</b><br>Expected (p(x)p(y)): <b>%.1f (%.2f%%)</b><br>Actual (p(x,y)): <b>%d (%.2f%%)</b>
                                <hr><b>Statistics:</b><br>Chi-square: <b>%.2f</b><br>Standardized Pearson residual: <b>%.2f</b>""" %(self.attrX, getHtmlCompatibleString(xAttr), xVal, 100.0*float(xVal)/float(sum_), self.attrY, getHtmlCompatibleString(yAttr), yVal, 100.0*float(yVal)/float(sum_), expected, 100.0*float(xVal*yVal)/float(sum_*sum_), actual, 100.0*float(actual)/float(sum_), chisquare, pearson )
                rect.setToolTip(tooltipText)

                currY += height
                if currX == xOff:
                    CanvasText(self.canvas, "", xOff, currY - height / 2, Qt.AlignRight | Qt.AlignVCenter, html_text= getHtmlCompatibleString(data.domain[self.attrY].values[j]))

            xl = CanvasText(self.canvas, "", currX + width / 2, yOff + sqareSize, Qt.AlignHCenter | Qt.AlignTop, html_text= getHtmlCompatibleString(data.domain[self.attrX].values[i]))
            max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h)

            currX += width

        # show attribute names
        CanvasText(self.canvas, self.attrY, 0, yOff + sqareSize / 2, Qt.AlignLeft | Qt.AlignVCenter, bold = 1, vertical=True)
        CanvasText(self.canvas, self.attrX, xOff + sqareSize / 2, yOff + sqareSize + max_xlabel_h, Qt.AlignHCenter | Qt.AlignTop, bold = 1)


    ######################################################################
    ## show deviations from attribute independence with standardized pearson residuals
    def addRectIndependencePearson(self, rect, x, y, w, h, xAttr_xVal, yAttr_yVal, actual, sum, width):
        xAttr, xVal = xAttr_xVal
        yAttr, yVal = yAttr_yVal
        expected = float(xVal*yVal)/float(sum)
        pearson = (actual - expected) / sqrt(expected)

        if pearson > 0:     # if there are more examples that we would expect under the null hypothesis
            intPearson = floor(pearson)
            pen = QPen(QColor(0,0,255), width); rect.setPen(pen)
            b = 255
            r = g = 255 - intPearson*20
            r = g = max(r, 55)  #
        elif pearson < 0:
            intPearson = ceil(pearson)
            pen = QPen(QColor(255,0,0), width)
            rect.setPen(pen)
            r = 255
            b = g = 255 + intPearson*20
            b = g = max(b, 55)
        else:
            pen = QPen(QColor(255,255,255), width)
            r = g = b = 255         # white
        color = QColor(r,g,b)
        brush = QBrush(color)
        rect.setBrush(brush)

        if pearson > 0:
            pearson = min(pearson, 10)
            kvoc = 1 - 0.08 * pearson       #  if pearson in [0..10] --> kvoc in [1..0.2]
        else:
            pearson = max(pearson, -10)
            kvoc = 1 - 0.4*pearson

        pen.setWidth(1)
        self.addLines(x,y,w,h, kvoc, pen)


    ##################################################
    # add lines
    def addLines(self, x, y, w, h, diff, pen):
        if w == 0 or h == 0:
            return

        dist = 20 * diff  # original distance between two lines in pixels
        temp = dist
        canvas = self.canvas
        while temp < w:
            r = QGraphicsLineItem(temp + x, y, temp + x, y + h, None)
            canvas.addItem(r)
            r.setPen(pen)
            temp += dist

        temp = dist
        while temp < h:
            r = QGraphicsLineItem(x, y + temp, x + w, y + temp, None)
            canvas.addItem(r)
            r.setPen(pen)
            temp += dist

    def closeEvent(self, ce):
        QDialog.closeEvent(self, ce)

    def get_widget_name_extension(self):
        if self.data is not None:
            return "{} vs {}".format(self.attrX, self.attrY)

    def send_report(self):
        self.report_plot()
Esempio n. 19
0
class ImagesPreviewer(foundations.ui.common.QWidgetFactory(uiFile=UI_FILE)):
	"""
	| This class provides the Application images previewer.
	| It defines methods to navigate through the list of given images ( List of images paths ),
		zoom in / out and fit the displayed image, etc...
	"""

	def __init__(self, parent, paths=None, *args, **kwargs):
		"""
		This method initializes the class.

		:param parent: Object parent. ( QObject )
		:param paths: Images paths. ( Tuple / List )
		:param \*args: Arguments. ( \* )
		:param \*\*kwargs: Keywords arguments. ( \*\* )
		"""

		LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))

		super(ImagesPreviewer, self).__init__(parent, *args, **kwargs)

		# --- Setting class attributes. ---
		self.__container = parent
		self.__paths = None
		self.paths = paths

		self.__uiResourcesDirectory = "resources"
		self.__uiResourcesDirectory = os.path.join(os.path.dirname(__file__), self.__uiResourcesDirectory)
		self.__uiPreviousImage = "Previous.png"
		self.__uiNextImage = "Next.png"
		self.__uiZoomOutImage = "Zoom_Out.png"
		self.__uiZoomInImage = "Zoom_In.png"

		# Ensure the ui object is destroyed on close to avoid memory leaks.
		self.setAttribute(Qt.WA_DeleteOnClose)

		self.__graphicsSceneBackgroundColor = QColor(32, 32, 32)
		self.__minimumZoomFactor = 0.05
		self.__maximumZoomFactor = 25
		self.__displayGraphicsItemMargin = 32
		self.__graphicsSceneWidth = QApplication.desktop().screenGeometry(
								QApplication.desktop().primaryScreen()).width() * (1 / self.__minimumZoomFactor * 1.75)
		self.__graphicsSceneHeight = QApplication.desktop().screenGeometry(
								QApplication.desktop().primaryScreen()).height() * (1 / self.__minimumZoomFactor * 1.75)
		self.__wheelZoomFactor = 350.0
		self.__keyZoomFactor = 1.20

		self.__graphicsView = None
		self.__graphicsScene = None
		self.__displayGraphicsItem = None

		ImagesPreviewer.__initializeUi(self)

		self.loadImage()

	#******************************************************************************************************************
	#***	Attributes properties.
	#******************************************************************************************************************
	@property
	def container(self):
		"""
		This method is the property for **self.__container** attribute.

		:return: self.__container. ( QObject )
		"""

		return self.__container

	@container.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def container(self, value):
		"""
		This method is the setter method for **self.__container** attribute.

		:param value: Attribute value. ( QObject )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "container"))

	@container.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def container(self):
		"""
		This method is the deleter method for **self.__container** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "container"))

	@property
	def paths(self):
		"""
		This method is the property for **self.__paths** attribute.

		:return: self.__paths. ( Tuple / List )
		"""

		return self.__paths

	@paths.setter
	@foundations.exceptions.handleExceptions(AssertionError)
	def paths(self, value):
		"""
		This method is the setter method for **self.__paths** attribute.

		:param value: Attribute value. ( Tuple / List )
		"""

		if value is not None:
			assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format("paths", value)
			for element in value:
				assert type(element) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
				"paths", element)
		self.__paths = value

	@paths.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def paths(self):
		"""
		This method is the deleter method for **self.__paths** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "paths"))

	@property
	def uiResourcesDirectory(self):
		"""
		This method is the property for **self.__uiResourcesDirectory** attribute.

		:return: self.__uiResourcesDirectory. ( String )
		"""

		return self.__uiResourcesDirectory

	@uiResourcesDirectory.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiResourcesDirectory(self, value):
		"""
		This method is the setter method for **self.__uiResourcesDirectory** attribute.

		:param value: Attribute value. ( String )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiResourcesDirectory"))

	@uiResourcesDirectory.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiResourcesDirectory(self):
		"""
		This method is the deleter method for **self.__uiResourcesDirectory** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiResourcesDirectory"))

	@property
	def uiPreviousImage(self):
		"""
		This method is the property for **self.__uiPreviousImage** attribute.

		:return: self.__uiPreviousImage. ( String )
		"""

		return self.__uiPreviousImage

	@uiPreviousImage.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiPreviousImage(self, value):
		"""
		This method is the setter method for **self.__uiPreviousImage** attribute.

		:param value: Attribute value. ( String )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiPreviousImage"))

	@uiPreviousImage.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiPreviousImage(self):
		"""
		This method is the deleter method for **self.__uiPreviousImage** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiPreviousImage"))

	@property
	def uiNextImage(self):
		"""
		This method is the property for **self.__uiNextImage** attribute.

		:return: self.__uiNextImage. ( String )
		"""

		return self.__uiNextImage

	@uiNextImage.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiNextImage(self, value):
		"""
		This method is the setter method for **self.__uiNextImage** attribute.

		:param value: Attribute value. ( String )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiNextImage"))

	@uiNextImage.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiNextImage(self):
		"""
		This method is the deleter method for **self.__uiNextImage** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiNextImage"))

	@property
	def uiZoomOutImage(self):
		"""
		This method is the property for **self.__uiZoomOutImage** attribute.

		:return: self.__uiZoomOutImage. ( String )
		"""

		return self.__uiZoomOutImage

	@uiZoomOutImage.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiZoomOutImage(self, value):
		"""
		This method is the setter method for **self.__uiZoomOutImage** attribute.

		:param value: Attribute value. ( String )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiZoomOutImage"))

	@uiZoomOutImage.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiZoomOutImage(self):
		"""
		This method is the deleter method for **self.__uiZoomOutImage** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiZoomOutImage"))

	@property
	def uiZoomInImage(self):
		"""
		This method is the property for **self.__uiZoomInImage** attribute.

		:return: self.__uiZoomInImage. ( String )
		"""

		return self.__uiZoomInImage

	@uiZoomInImage.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiZoomInImage(self, value):
		"""
		This method is the setter method for **self.__uiZoomInImage** attribute.

		:param value: Attribute value. ( String )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "uiZoomInImage"))

	@uiZoomInImage.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def uiZoomInImage(self):
		"""
		This method is the deleter method for **self.__uiZoomInImage** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiZoomInImage"))

	@property
	def graphicsSceneBackgroundColor(self):
		"""
		This method is the property for **self.__graphicsSceneBackgroundColor** attribute.

		:return: self.__graphicsSceneBackgroundColor. ( QColors )
		"""

		return self.__graphicsSceneBackgroundColor

	@graphicsSceneBackgroundColor.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsSceneBackgroundColor(self, value):
		"""
		This method is the setter method for **self.__graphicsSceneBackgroundColor** attribute.

		:param value: Attribute value. ( QColors )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsSceneBackgroundColor"))

	@graphicsSceneBackgroundColor.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsSceneBackgroundColor(self):
		"""
		This method is the deleter method for **self.__graphicsSceneBackgroundColor** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsSceneBackgroundColor"))

	@property
	def graphicsSceneWidth(self):
		"""
		This method is the property for **self.__graphicsSceneWidth** attribute.

		:return: self.__graphicsSceneWidth. ( Integer )
		"""

		return self.__graphicsSceneWidth

	@graphicsSceneWidth.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsSceneWidth(self, value):
		"""
		This method is the setter method for **self.__graphicsSceneWidth** attribute.

		:param value: Attribute value. ( Integer )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsSceneWidth"))

	@graphicsSceneWidth.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsSceneWidth(self):
		"""
		This method is the deleter method for **self.__graphicsSceneWidth** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsSceneWidth"))

	@property
	def graphicsSceneHeight(self):
		"""
		This method is the property for **self.__graphicsSceneHeight** attribute.

		:return: self.__graphicsSceneHeight. ( Object )
		"""

		return self.__graphicsSceneHeight

	@graphicsSceneHeight.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsSceneHeight(self, value):
		"""
		This method is the setter method for **self.__graphicsSceneHeight** attribute.

		:param value: Attribute value. ( Object )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsSceneHeight"))

	@graphicsSceneHeight.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsSceneHeight(self):
		"""
		This method is the deleter method for **self.__graphicsSceneHeight** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsSceneHeight"))

	@property
	def minimumZoomFactor(self):
		"""
		This method is the property for **self.__minimumZoomFactor** attribute.

		:return: self.__minimumZoomFactor. ( Float )
		"""

		return self.__minimumZoomFactor

	@minimumZoomFactor.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def minimumZoomFactor(self, value):
		"""
		This method is the setter method for **self.__minimumZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "minimumZoomFactor"))

	@minimumZoomFactor.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def minimumZoomFactor(self):
		"""
		This method is the deleter method for **self.__minimumZoomFactor** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "minimumZoomFactor"))

	@property
	def maximumZoomFactor(self):
		"""
		This method is the property for **self.__maximumZoomFactor** attribute.

		:return: self.__maximumZoomFactor. ( Float )
		"""

		return self.__maximumZoomFactor

	@maximumZoomFactor.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def maximumZoomFactor(self, value):
		"""
		This method is the setter method for **self.__maximumZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "maximumZoomFactor"))

	@maximumZoomFactor.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def maximumZoomFactor(self):
		"""
		This method is the deleter method for **self.__maximumZoomFactor** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "maximumZoomFactor"))

	@property
	def wheelZoomFactor(self):
		"""
		This method is the property for **self.__wheelZoomFactor** attribute.

		:return: self.__wheelZoomFactor. ( Float )
		"""

		return self.__wheelZoomFactor

	@wheelZoomFactor.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def wheelZoomFactor(self, value):
		"""
		This method is the setter method for **self.__wheelZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "wheelZoomFactor"))

	@wheelZoomFactor.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def wheelZoomFactor(self):
		"""
		This method is the deleter method for **self.__wheelZoomFactor** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "wheelZoomFactor"))

	@property
	def keyZoomFactor(self):
		"""
		This method is the property for **self.__keyZoomFactor** attribute.

		:return: self.__keyZoomFactor. ( Float )
		"""

		return self.__keyZoomFactor

	@keyZoomFactor.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def keyZoomFactor(self, value):
		"""
		This method is the setter method for **self.__keyZoomFactor** attribute.

		:param value: Attribute value. ( Float )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "keyZoomFactor"))

	@keyZoomFactor.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def keyZoomFactor(self):
		"""
		This method is the deleter method for **self.__keyZoomFactor** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "keyZoomFactor"))

	@property
	def graphicsView(self):
		"""
		This method is the property for **self.__graphicsView** attribute.

		:return: self.__graphicsView. ( QGraphicsView )
		"""

		return self.__graphicsView

	@graphicsView.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsView(self, value):
		"""
		This method is the setter method for **self.__graphicsView** attribute.

		:param value: Attribute value. ( QGraphicsView )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsView"))

	@graphicsView.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsView(self):
		"""
		This method is the deleter method for **self.__graphicsView** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsView"))

	@property
	def graphicsScene(self):
		"""
		This method is the property for **self.__graphicsScene** attribute.

		:return: self.__graphicsScene. ( QGraphicsScene )
		"""

		return self.__graphicsScene

	@graphicsScene.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsScene(self, value):
		"""
		This method is the setter method for **self.__graphicsScene** attribute.

		:param value: Attribute value. ( QGraphicsScene )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "graphicsScene"))

	@graphicsScene.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def graphicsScene(self):
		"""
		This method is the deleter method for **self.__graphicsScene** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "graphicsScene"))

	@property
	def displayGraphicsItem(self):
		"""
		This method is the property for **self.__displayGraphicsItem** attribute.

		:return: self.__displayGraphicsItem. ( QGraphicsItem )
		"""

		return self.__displayGraphicsItem

	@displayGraphicsItem.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def displayGraphicsItem(self, value):
		"""
		This method is the setter method for **self.__displayGraphicsItem** attribute.

		:param value: Attribute value. ( QGraphicsItem )
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "displayGraphicsItem"))

	@displayGraphicsItem.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def displayGraphicsItem(self):
		"""
		This method is the deleter method for **self.__displayGraphicsItem** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "displayGraphicsItem"))

	#******************************************************************************************************************
	#***	Class methods.
	#******************************************************************************************************************
	def show(self):
		"""
		This method reimplements the :meth:`QWidget.show` method.
		"""

		super(ImagesPreviewer, self).show()

		foundations.ui.common.centerWidgetOnScreen(self)

	def closeEvent(self, event):
		"""
		This method reimplements the :meth:`QWidget.closeEvent` method.

		:param event: QEvent ( QEvent )
		"""

		LOGGER.debug("> Removing '{0}' from Images Previewers list.".format(self))
		self.__container.imagesPreviewers.remove(self)

		event.accept()

	def wheelEvent(self, event):
		"""
		This method reimplements the :meth:`QWidget.wheelEvent` method.

		:param event: QEvent ( QEvent )
		"""

		self.scaleView(pow(1.5, event.delta() / self.__wheelZoomFactor))

	def keyPressEvent(self, event):
		"""
		This method reimplements the :meth:`QWidget.keyPressEvent` method.

		:param event: QEvent ( QEvent )
		"""

		key = event.key()
		if key == Qt.Key_Plus:
			self.scaleView(self.__keyZoomFactor)
		elif key == Qt.Key_Minus:
			self.scaleView(1 / self.__keyZoomFactor)
		else:
			super(ImagesPreviewer, self).keyPressEvent(event)

	def __initializeUi(self):
		"""
		This method initializes the Widget ui.
		"""

		LOGGER.debug("> Initializing '{0}' ui.".format(self.__class__.__name__))

		self.Previous_Image_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiPreviousImage)))
		self.Next_Image_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiNextImage)))
		self.Zoom_In_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiZoomInImage)))
		self.Zoom_Out_pushButton.setIcon(QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiZoomOutImage)))
		len(self.__paths) <= 1 and self.Navigation_frame.hide()

		LOGGER.debug("> Initializing graphics View.")
		self.__graphicsView = QGraphicsView()
		self.__graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
		self.__graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
		self.__graphicsView.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
		self.__graphicsView.setDragMode(QGraphicsView.ScrollHandDrag)
		# Reimplementing QGraphicsView wheelEvent method.
		self.__graphicsView.wheelEvent = self.wheelEvent

		LOGGER.debug("> Initializing graphics scene.")
		self.__graphicsScene = QGraphicsScene(self.__graphicsView)
		self.__graphicsScene.setItemIndexMethod(QGraphicsScene.NoIndex)
		self.__graphicsScene.setSceneRect(-(float(self.__graphicsSceneWidth)) / 2,
										- (float(self.__graphicsSceneHeight)) / 2,
										float(self.__graphicsSceneWidth),
										float(self.__graphicsSceneHeight))

		self.__graphicsView.setScene(self.__graphicsScene)
		self.__graphicsView.setBackgroundBrush(QBrush(self.__graphicsSceneBackgroundColor))

		self.Images_Previewer_frame_gridLayout.addWidget(self.__graphicsView)

		# Signals / Slots.
		self.__container.engine.imagesCaches.QImage.contentAdded.connect(self.__engine_imagesCaches_QImage__contentAdded)
		self.Previous_Image_pushButton.clicked.connect(self.__Previous_Image_pushButton__clicked)
		self.Next_Image_pushButton.clicked.connect(self.__Next_Image_pushButton__clicked)
		self.Zoom_Out_pushButton.clicked.connect(self.__Zoom_Out_pushButton__clicked)
		self.Zoom_In_pushButton.clicked.connect(self.__Zoom_In_pushButton__clicked)
		self.Zoom_Fit_pushButton.clicked.connect(self.__Zoom_Fit_pushButton__clicked)

	def __Images_Informations_label_setUi(self):
		"""
		This method sets the **Images_Informations_label** Widget ui.
		"""

		if not self.__displayGraphicsItem:
			return

		image = self.__displayGraphicsItem.image
		self.Images_Informations_label.setText("{0} - {1}x{2} px - {3} bit".format(os.path.basename(image.data.path),
		 																		image.data.width,
																				image.data.height,
																				image.data.bpp / 4))

	def __engine_imagesCaches_QImage__contentAdded(self, content):
		"""
		This method is triggered by the Application **QImage** images cache when content has been added.

		:param content: Cache added content. ( List )
		"""

		if not self.__paths:
			return

		path = foundations.common.getFirstItem(content)
		if not path in self.__paths:
			return

		image = self.__container.engine.imagesCaches.QImage.getContent(path)
		self.__setDisplayGraphicsItem(image)

	def __Previous_Image_pushButton__clicked(self, checked):
		"""
		This method is triggered when **Previous_Image_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

		self.loopThroughImages(True)

	def __Next_Image_pushButton__clicked(self, checked):
		"""
		This method is triggered when **Next_Image_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

		self.loopThroughImages()

	def __Zoom_In_pushButton__clicked(self, checked):
		"""
		This method is triggered when **Zoom_In_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

		self.scaleView(self.__keyZoomFactor)

	def __Zoom_Out_pushButton__clicked(self, checked):
		"""
		This method is triggered when **Zoom_Out_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

		self.scaleView(1 / self.__keyZoomFactor)

	def __Zoom_Fit_pushButton__clicked(self, checked):
		"""
		This method is triggered when **Zoom_Fit_pushButton** Widget is clicked.

		:param checked: Checked state. ( Boolean )
		"""

		self.fitImage()

	def __clearGraphicsScene(self):
		"""
		This method clears the View.
		"""

		for graphicsItem in self.__graphicsScene.items():
			self.__graphicsScene.removeItem(graphicsItem)

	def __setDisplayGraphicsItem(self, image):
		"""
		This method sets the View using given image.

		:param image: Image to display. ( Qimage )
		"""

		self.__clearGraphicsScene()

		LOGGER.debug("> Initializing graphics item.")
		self.__displayGraphicsItem = Image_QGraphicsItem(image=image)
		self.__graphicsScene.addItem(self.__displayGraphicsItem)

		self.__Images_Informations_label_setUi()

	def loadImage(self, index=0):
		"""
		This method loads the display image in the View.

		:param index: Index to load. ( Integer )
		:return: Method success. ( Boolean )
		"""

		if not self.__paths:
			return False

		image = sibl_gui.ui.common.getImage(self.__paths[index])
		self.__setDisplayGraphicsItem(image)

		return True

	def scaleView(self, scaleFactor):
		"""
		This method scales the Previewer view.

		:param scaleFactor: Float ( Float )
		:return: Method success. ( Boolean )
		"""

		graphicsView = self.findChild(QGraphicsView)
		factor = graphicsView.matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width()
		if factor < self.__minimumZoomFactor or factor > self.__maximumZoomFactor:
			return False

		graphicsView.scale(scaleFactor, scaleFactor)
		return True

	def fitWindow(self):
		"""
		This method fits the View window.
		
		:return: Method success. ( Boolean )
		"""

		if not self.__displayGraphicsItem:
			return False

		desktopWidth = QApplication.desktop().screenGeometry(QApplication.desktop().primaryScreen()).width()
		desktopHeight = QApplication.desktop().screenGeometry(QApplication.desktop().primaryScreen()).height()
		width = min(desktopWidth * 0.80, self.__displayGraphicsItem.width)
		height = min(desktopHeight * 0.80, self.__displayGraphicsItem.height)
		self.resize(width, height)

		foundations.ui.common.centerWidgetOnScreen(self)

		return True

	def fitImage(self):
		"""
		This method fits the image to the View.
		
		:return: Method success. ( Boolean )
		"""

		if not self.__displayGraphicsItem:
			return False

		self.__graphicsView.fitInView(
		QRectF(-(self.__displayGraphicsItem.width / 2) - (self.__displayGraphicsItemMargin / 2),
				- (self.__displayGraphicsItem.height / 2) - (self.__displayGraphicsItemMargin / 2),
				self.__displayGraphicsItem.width + self.__displayGraphicsItemMargin,
				self.__displayGraphicsItem.height + self.__displayGraphicsItemMargin),
				Qt.KeepAspectRatio)
		return True

	def loopThroughImages(self, backward=False):
		"""
		This method loops through View images.

		:param backward: Looping backward. ( Boolean )
		:return: Method success. ( Boolean )
		"""

		index = self.__paths.index(self.__displayGraphicsItem.image.data.path)
		index += not backward and 1 or -1
		if index < 0:
			index = len(self.__paths) - 1
		elif index > len(self.__paths) - 1:
			index = 0
		self.loadImage(index)
		return True
Esempio n. 20
0
class OWSieveDiagram(OWWidget):
    name = "Sieve Diagram"
    description = "A two-way contingency table providing information in " \
                  "relation to expected frequency of combination of feature " \
                  "values under independence."
    icon = "icons/SieveDiagram.svg"
    priority = 4200

    inputs = [("Data", Table, "set_data", Default),
              ("Features", AttributeList, "set_input_features")]
    outputs = [("Selection", Table)]

    graph_name = "canvas"

    want_control_area = False

    settingsHandler = DomainContextHandler()
    attrX = ContextSetting("")
    attrY = ContextSetting("")
    selection = ContextSetting(set())

    def __init__(self):
        super().__init__()

        self.data = None
        self.input_features = None
        self.attrs = []

        self.attr_box = gui.hBox(self.mainArea)
        model = VariableListModel()
        model.wrap(self.attrs)
        self.attrXCombo = gui.comboBox(self.attr_box,
                                       self,
                                       value="attrX",
                                       contentsLength=12,
                                       callback=self.change_attr,
                                       sendSelectedValue=True,
                                       valueType=str)
        self.attrXCombo.setModel(model)
        gui.widgetLabel(self.attr_box, "\u2715").\
            setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.attrYCombo = gui.comboBox(self.attr_box,
                                       self,
                                       value="attrY",
                                       contentsLength=12,
                                       callback=self.change_attr,
                                       sendSelectedValue=True,
                                       valueType=str)
        self.attrYCombo.setModel(model)

        self.canvas = QGraphicsScene()
        self.canvasView = ViewWithPress(self.canvas,
                                        self.mainArea,
                                        handler=self.reset_selection)
        self.mainArea.layout().addWidget(self.canvasView)
        self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        box = gui.hBox(self.mainArea)
        gui.button(box,
                   None,
                   "&Save Graph",
                   callback=self.save_graph,
                   autoDefault=False)
        gui.button(box,
                   None,
                   "&Report",
                   callback=self.show_report,
                   autoDefault=False)

    def sizeHint(self):
        return QSize(450, 550)

    def set_data(self, data):
        if type(data) == SqlTable and data.approx_len() > LARGE_TABLE:
            data = data.sample_time(DEFAULT_SAMPLE_TIME)

        self.closeContext()
        self.data = data
        self.areas = []
        if self.data is None:
            self.attrs[:] = []
        else:
            self.attrs[:] = [
                var for var in chain(self.data.domain, self.data.domain.metas)
                if var.is_discrete
            ]
        if self.attrs:
            self.attrX = self.attrs[0].name
            self.attrY = self.attrs[len(self.attrs) > 1].name
        else:
            self.attrX = self.attrY = None
        self.openContext(self.data)

        self.information(0, "")
        if data and any(attr.is_continuous for attr in data.domain):
            self.information(
                0, "Data contains continuous variables. "
                "Discretize the data to use them.")
        self.resolve_shown_attributes()
        self.update_selection()

    def change_attr(self):
        self.selection = set()
        self.updateGraph()
        self.update_selection()

    def set_input_features(self, attrList):
        self.input_features = attrList
        self.resolve_shown_attributes()
        self.update_selection()

    def resolve_shown_attributes(self):
        self.warning(1)
        self.attr_box.setEnabled(True)
        if self.input_features:  # non-None and non-empty!
            features = [f for f in self.input_features if f in self.attrs]
            if not features:
                self.warning(
                    1, "Features from the input signal "
                    "are not present in the data")
            else:
                old_attrs = self.attrX, self.attrY
                self.attrX, self.attrY = [f.name for f in (features * 2)[:2]]
                self.attr_box.setEnabled(False)
                if (self.attrX, self.attrY) != old_attrs:
                    self.selection = set()
        # else: do nothing; keep current features, even if input with the
        # features just changed to None
        self.updateGraph()

    def resizeEvent(self, e):
        OWWidget.resizeEvent(self, e)
        self.updateGraph()

    def showEvent(self, ev):
        OWWidget.showEvent(self, ev)
        self.updateGraph()

    def reset_selection(self):
        self.selection = set()
        self.update_selection()

    def select_area(self, area, ev):
        if ev.button() != Qt.LeftButton:
            return
        index = self.areas.index(area)
        if ev.modifiers() & Qt.ControlModifier:
            self.selection ^= {index}
        else:
            self.selection = {index}
        self.update_selection()

    def update_selection(self):
        if self.areas is None or not self.selection:
            self.send("Selection", None)
            return

        filters = []
        for i, area in enumerate(self.areas):
            if i in self.selection:
                width = 4
                val_x, val_y = area.value_pair
                filters.append(
                    filter.Values([
                        filter.FilterDiscrete(self.attrX, [val_x]),
                        filter.FilterDiscrete(self.attrY, [val_y])
                    ]))
            else:
                width = 1
            pen = area.pen()
            pen.setWidth(width)
            area.setPen(pen)
        if len(filters) == 1:
            filters = filters[0]
        else:
            filters = filter.Values(filters, conjunction=False)
        self.send("Selection", filters(self.data))

    # -----------------------------------------------------------------------
    # Everything from here on is ancient and has been changed only according
    # to what has been changed above. Some clean-up may be in order some day
    #
    def updateGraph(self, *args):
        for item in self.canvas.items():
            self.canvas.removeItem(item)
        if self.data is None or len(self.data) == 0 or \
                self.attrX is None or self.attrY is None:
            return
        data = self.data[:, [self.attrX, self.attrY]]
        valsX = []
        valsY = []
        contX = get_contingency(data, self.attrX, self.attrX)
        contY = get_contingency(data, self.attrY, self.attrY)
        # compute contingency of x and y attributes
        for entry in contX:
            sum_ = 0
            try:
                for val in entry:
                    sum_ += val
            except:
                pass
            valsX.append(sum_)

        for entry in contY:
            sum_ = 0
            try:
                for val in entry:
                    sum_ += val
            except:
                pass
            valsY.append(sum_)

        contXY, _ = get_conditional_distribution(
            data, [data.domain[self.attrX], data.domain[self.attrY]])
        # compute probabilities
        probs = {}
        for i in range(len(valsX)):
            valx = valsX[i]
            for j in range(len(valsY)):
                valy = valsY[j]
                try:
                    actualProb = contXY['%s-%s' %
                                        (data.domain[self.attrX].values[i],
                                         data.domain[self.attrY].values[j])]
                    # for val in contXY['%s-%s' %(i, j)]: actualProb += val
                except:
                    actualProb = 0
                probs['%s-%s' % (data.domain[self.attrX].values[i],
                                 data.domain[self.attrY].values[j])] = ((
                                     data.domain[self.attrX].values[i],
                                     valx), (data.domain[self.attrY].values[j],
                                             valy), actualProb, len(data))

        #get text width of Y labels
        max_ylabel_w = 0
        for j in range(len(valsY)):
            xl = CanvasText(self.canvas,
                            "",
                            0,
                            0,
                            html_text=getHtmlCompatibleString(
                                data.domain[self.attrY].values[j]),
                            show=False)
            max_ylabel_w = max(int(xl.boundingRect().width()), max_ylabel_w)
        max_ylabel_w = min(max_ylabel_w, 200)  #upper limit for label widths
        # get text width of Y attribute name
        text = CanvasText(self.canvas,
                          data.domain[self.attrY].name,
                          x=0,
                          y=0,
                          bold=1,
                          show=0,
                          vertical=True)
        xOff = int(text.boundingRect().height() + max_ylabel_w)
        yOff = 55
        sqareSize = min(self.canvasView.width() - xOff - 35,
                        self.canvasView.height() - yOff - 50)
        sqareSize = max(sqareSize, 10)
        self.canvasView.setSceneRect(0, 0, self.canvasView.width(),
                                     self.canvasView.height())

        # print graph name
        name = "<b>P(%s, %s) &#8800; P(%s)&times;P(%s)</b>" % (
            self.attrX, self.attrY, self.attrX, self.attrY)
        CanvasText(self.canvas,
                   "",
                   xOff + sqareSize / 2,
                   20,
                   Qt.AlignCenter,
                   html_text=name)
        CanvasText(self.canvas,
                   "N = " + str(len(data)),
                   xOff + sqareSize / 2,
                   38,
                   Qt.AlignCenter,
                   bold=0)

        ######################
        # compute chi-square
        chisquare = 0.0
        for i in range(len(valsX)):
            for j in range(len(valsY)):
                ((xAttr, xVal), (yAttr, yVal), actual,
                 sum_) = probs['%s-%s' % (data.domain[self.attrX].values[i],
                                          data.domain[self.attrY].values[j])]
                expected = float(xVal * yVal) / float(sum_)
                if expected == 0: continue
                pearson2 = (actual - expected) * (actual - expected) / expected
                chisquare += pearson2

        ######################
        # draw rectangles
        currX = xOff
        max_xlabel_h = 0
        normX, normY = sum(valsX), sum(valsY)
        self.areas = []
        for i in range(len(valsX)):
            if valsX[i] == 0: continue
            currY = yOff
            width = int(float(sqareSize * valsX[i]) / float(normX))

            for j in range(len(valsY) - 1, -1,
                           -1):  # this way we sort y values correctly
                ((xAttr, xVal), (yAttr, yVal), actual,
                 sum_) = probs['%s-%s' % (data.domain[self.attrX].values[i],
                                          data.domain[self.attrY].values[j])]
                if valsY[j] == 0: continue
                height = int(float(sqareSize * valsY[j]) / float(normY))

                # create rectangle
                selected = len(self.areas) in self.selection
                rect = CanvasRectangle(self.canvas,
                                       currX + 2,
                                       currY + 2,
                                       width - 4,
                                       height - 4,
                                       z=-10,
                                       onclick=self.select_area)
                rect.value_pair = i, j
                self.areas.append(rect)
                self.addRectIndependencePearson(
                    rect,
                    currX + 2,
                    currY + 2,
                    width - 4,
                    height - 4,
                    (xAttr, xVal),
                    (yAttr, yVal),
                    actual,
                    sum_,
                    width=1 + 3 * selected,  # Ugly! This is needed since
                    # resize redraws the graph! When this is handled by resizing
                    # just the viewer, update_selection will take care of this
                )

                expected = float(xVal * yVal) / float(sum_)
                pearson = (actual - expected) / sqrt(expected)
                tooltipText = """<b>X Attribute: %s</b><br>Value: <b>%s</b><br>Number of instances (p(x)): <b>%d (%.2f%%)</b><hr>
                                <b>Y Attribute: %s</b><br>Value: <b>%s</b><br>Number of instances (p(y)): <b>%d (%.2f%%)</b><hr>
                                <b>Number Of Instances (Probabilities):</b><br>Expected (p(x)p(y)): <b>%.1f (%.2f%%)</b><br>Actual (p(x,y)): <b>%d (%.2f%%)</b>
                                <hr><b>Statistics:</b><br>Chi-square: <b>%.2f</b><br>Standardized Pearson residual: <b>%.2f</b>""" % (
                    self.attrX, getHtmlCompatibleString(xAttr), xVal,
                    100.0 * float(xVal) / float(sum_), self.attrY,
                    getHtmlCompatibleString(yAttr), yVal,
                    100.0 * float(yVal) / float(sum_), expected,
                    100.0 * float(xVal * yVal) / float(sum_ * sum_), actual,
                    100.0 * float(actual) / float(sum_), chisquare, pearson)
                rect.setToolTip(tooltipText)

                currY += height
                if currX == xOff:
                    CanvasText(self.canvas,
                               "",
                               xOff,
                               currY - height / 2,
                               Qt.AlignRight | Qt.AlignVCenter,
                               html_text=getHtmlCompatibleString(
                                   data.domain[self.attrY].values[j]))

            xl = CanvasText(self.canvas,
                            "",
                            currX + width / 2,
                            yOff + sqareSize,
                            Qt.AlignHCenter | Qt.AlignTop,
                            html_text=getHtmlCompatibleString(
                                data.domain[self.attrX].values[i]))
            max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h)

            currX += width

        # show attribute names
        CanvasText(self.canvas,
                   self.attrY,
                   0,
                   yOff + sqareSize / 2,
                   Qt.AlignLeft | Qt.AlignVCenter,
                   bold=1,
                   vertical=True)
        CanvasText(self.canvas,
                   self.attrX,
                   xOff + sqareSize / 2,
                   yOff + sqareSize + max_xlabel_h,
                   Qt.AlignHCenter | Qt.AlignTop,
                   bold=1)

    ######################################################################
    ## show deviations from attribute independence with standardized pearson residuals
    def addRectIndependencePearson(self, rect, x, y, w, h, xAttr_xVal,
                                   yAttr_yVal, actual, sum, width):
        xAttr, xVal = xAttr_xVal
        yAttr, yVal = yAttr_yVal
        expected = float(xVal * yVal) / float(sum)
        pearson = (actual - expected) / sqrt(expected)

        if pearson > 0:  # if there are more examples that we would expect under the null hypothesis
            intPearson = floor(pearson)
            pen = QPen(QColor(0, 0, 255), width)
            rect.setPen(pen)
            b = 255
            r = g = 255 - intPearson * 20
            r = g = max(r, 55)  #
        elif pearson < 0:
            intPearson = ceil(pearson)
            pen = QPen(QColor(255, 0, 0), width)
            rect.setPen(pen)
            r = 255
            b = g = 255 + intPearson * 20
            b = g = max(b, 55)
        else:
            pen = QPen(QColor(255, 255, 255), width)
            r = g = b = 255  # white
        color = QColor(r, g, b)
        brush = QBrush(color)
        rect.setBrush(brush)

        if pearson > 0:
            pearson = min(pearson, 10)
            kvoc = 1 - 0.08 * pearson  #  if pearson in [0..10] --> kvoc in [1..0.2]
        else:
            pearson = max(pearson, -10)
            kvoc = 1 - 0.4 * pearson

        pen.setWidth(1)
        self.addLines(x, y, w, h, kvoc, pen)

    ##################################################
    # add lines
    def addLines(self, x, y, w, h, diff, pen):
        if w == 0 or h == 0:
            return

        dist = 20 * diff  # original distance between two lines in pixels
        temp = dist
        canvas = self.canvas
        while temp < w:
            r = QGraphicsLineItem(temp + x, y, temp + x, y + h, None)
            canvas.addItem(r)
            r.setPen(pen)
            temp += dist

        temp = dist
        while temp < h:
            r = QGraphicsLineItem(x, y + temp, x + w, y + temp, None)
            canvas.addItem(r)
            r.setPen(pen)
            temp += dist

    def closeEvent(self, ce):
        QDialog.closeEvent(self, ce)

    def get_widget_name_extension(self):
        if self.data is not None:
            return "{} vs {}".format(self.attrX, self.attrY)

    def send_report(self):
        self.report_plot()
Esempio n. 21
0
class Window(QWidget):
    ''' The MainWindow widget '''
    def __init__(self, game):
        super().__init__()

        self.game = game
        self.game.ui = self

        self.setWindowTitle('WordJuggler')
        self.resize(800, 600)
        self.setStyleSheet('QGroupBox { border:0; font:bold;' +
                           'padding:20px 10px; min-width:220px; }')

        self.board = BoardItem(game.width, game.height)
        self.rack = RackItem(game.rack_size, game.width, game.height)
        self.scene = QGraphicsScene()
        self.scene.setBackgroundBrush(QBrush(QColor('#f9ece0')))
        self.scene.addItem(self.board)
        self.scene.addItem(self.rack)
        self.scene.setSceneRect(self.scene.itemsBoundingRect())
        self.view = BoardView(self.scene, self)
        self.view.letterChanged.connect(self.letterChanged)

        self.ranking = QGroupBox('Rankings')
        self.rankings = QLabel()
        rankings = QVBoxLayout()
        rankings.addWidget(self.rankings)
        self.ranking.setLayout(rankings)

        self.statistic = QGroupBox('Statistics')
        self.statistics = QLabel()
        statistics = QVBoxLayout()
        statistics.addWidget(self.statistics)
        self.statistic.setLayout(statistics)

        self.move = QGroupBox('Last 10 Moves')
        self.moves = QLabel()
        moves = QVBoxLayout()
        moves.addWidget(self.moves)
        self.move.setLayout(moves)

        self.buttons = QVBoxLayout()
        self.buttons.setSpacing(3)
        self.continue_button = QPushButton('Place &Word')
        self.continue_button.setEnabled(False)
        self.continue_button.setFixedSize(130, 25)
        self.continue_button.clicked.connect(self.continueClicked)
        self.pass_button = QPushButton('&Pass')
        self.pass_button.setEnabled(False)
        self.pass_button.setFixedSize(130, 25)
        self.pass_button.clicked.connect(self.passClicked)
        self.exchange_button = QPushButton('&Exchange')
        self.exchange_button.setEnabled(False)
        self.exchange_button.setFixedSize(130, 25)
        self.exchange_button.clicked.connect(self.exchangeClicked)
        self.buttons.addWidget(self.exchange_button, alignment=Qt.AlignCenter)
        self.buttons.addWidget(self.pass_button, alignment=Qt.AlignCenter)
        self.buttons.addWidget(self.continue_button, alignment=Qt.AlignCenter)

        information = QVBoxLayout()
        information.setMargin(20)
        information.setSpacing(20)
        information.addWidget(self.ranking)
        information.addWidget(self.statistic)
        information.addWidget(self.move)
        information.addStretch()
        information.addLayout(self.buttons)

        layout = QHBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.view)
        layout.addLayout(information)

        self.setLayout(layout)
        self.show()

        for player in self.game.players:
            player.played_cb = self.playerDone
        self.playerNext()

    def update(self, *args, **kwargs):
        self.rankings.setText(
            '<br>'.join('%i. <font color=%s>%s</font> (%i points)' %
                        (i + 1, player.color, player.name, player.score)
                        for i,player in
                        enumerate(sorted(self.game.players, reverse=True,
                                         key=attrgetter('score')))))
        self.statistics.setText(('Total Players: %i\n' +
                                 'Placed Words: %i\n' +
                                 'Remaining Letters: %i') %
                                (len(self.game.players),
                                 len(list(self.game.board.get_words())),
                                 self.game.letters.remaining_letters))
        moves = []
        for i,(player,move) in list(enumerate(self.game.moves))[-10:]:
            if move[0] == Player.PASS:
                desc = 'Pass'
            elif move[0] == Player.EXCHANGE_LETTERS:
                desc = 'Exchange (%s,%s)' % move[1:]
            else:
                desc = 'Word (%i,%i,%s,%s,%i)' % move[1:]
            moves.append('%i. <font color=%s>%s</font>' % (i + 1, player.color,
                                                           desc))
        self.moves.setText('<br>'.join(moves))

        super().update(*args, **kwargs)

    def letterChanged(self):
        ''' As soon as a letter changes we need to en/disable all controls '''
        self.exchange_button.setEnabled(False)
        self.exchange_button.setText('Exchange')
        if self.game.letters.remaining_letters >= self.game.rack_size:
            selected = ''.join(l.char for l in self.scene.items()
                               if type(l) is LetterItem and l.selected)
            if selected:
                self.exchange_button.setText('Exchange: %s' % selected)
                self.exchange_button.setEnabled(True)
        self.pass_button.setEnabled(True)
        self.continue_button.setEnabled(True if self.board.validNewWord() else
                                        False)

    def playerNext(self):
        player = self.game.next_player()

        self.letterChanged()
        self.update()
        player.update_letters()

        self.rack.name = self.game.current_player.name
        self.rack.color = self.game.current_player.color

        for i,letter in enumerate(player.letters):
            item = LetterItem(letter, self.game.letters.get_score(letter),
                              player.color)
            item.own(self.rack, i, move=False)
            self.scene.addItem(item)

        self.update()
        player.played_cb = self.playerDone
        player.play()

    def continueClicked(self):
        if type(self.game.current_player) is Human:
            self.game.current_player.continue_cb()

    def passClicked(self):
        if type(self.game.current_player) is Human:
            self.game.current_player.pass_cb()

    def exchangeClicked(self):
        if type(self.game.current_player) is Human:
            self.game.current_player.exchange_cb()

    def playerDone(self, player, move, *args):
        self.exchange_button.setEnabled(False)
        self.exchange_button.setText('Exchange')
        self.pass_button.setEnabled(False)
        self.continue_button.setEnabled(False)

        for item in self.scene.items():
            if type(item) is LetterItem and not item.is_safe and \
               not item.deleted:
                item.own(None)
                item.fade()

        for x,y,letter in self.game.board:
            if not self.board.getLetter(x, y):
                item = LetterItem(letter.char,
                                  self.game.letters.get_score(letter),
                                  letter.player.color, safe=True)
                item.own(self.board, x, y, move=False)
                self.scene.addItem(item)

        self.update()

        if self.game.state() == self.game.RUNNING:
            self.game.current_player.update_letters()
            self.playerNext()
        else:
            self.game.finish_score()
            self.update()
            self.gameOver()
        
    def getLetters(self, count, msg=''):
        print('random letters: %s' % self.game.get_letters_old(count))
        while True:
            text,ok = QInputDialog.getText(self, 'New Letters',
                'Player: <font color=%s>%s</font><br>' % (
                self.game.current_player.color, self.game.current_player.name)
                + msg + 'Tell me %i new letters in order to continue..' % count)

            text = ''.join(filter(lambda x: x in self.game.letters.letters,
                                  text.lower()))

            if len(text) == count and all(self.game.letters.available(c) for c
                                          in text):
                return text

    def gameOver(self):
        winner = sorted(self.game.players, reverse=True,
                        key=attrgetter('score'))[0]
        self.dialog = QMessageBox(QMessageBox.Information, 'Game Over',
            ('<b>Game Over!</b><br><br>The player ' +
             '<b><font color=%s>%s</font></b> has won!') %
            (winner.color, winner.name),
            QMessageBox.Ok, self)
        self.dialog.show()