示例#1
0
    def __init__(self, parent=None, signalManager=None):
        OWWidget.__init__(self, parent, signalManager, "Parallel Coordinates",
                          TRUE)

        #add a graph widget
        self.graph = OWParallelGraph(self, self.mainArea)
        self.mainArea.layout().addWidget(self.graph)

        self.showAllAttributes = 0

        self.inputs = [("Data", ExampleTable, self.setData, Default),
                       ("Data Subset", ExampleTable, self.setSubsetData),
                       ("Features", AttributeList, self.setShownAttributes)]
        self.outputs = [("Selected Data", ExampleTable),
                        ("Other Data", ExampleTable),
                        ("Features", AttributeList)]

        #set default settings
        self.data = None
        self.subsetData = None
        self.autoSendSelection = 1
        self.attrDiscOrder = "Unordered"
        self.attrContOrder = "Unordered"
        self.projections = None
        self.correlationDict = {}
        self.middleLabels = "Correlations"
        self.attributeSelectionList = None
        self.toolbarSelection = 0
        self.colorSettings = None
        self.selectedSchemaIndex = 0

        self.graph.jitterSize = 10
        self.graph.showDistributions = 1
        self.graph.showStatistics = 0
        self.graph.showAttrValues = 1
        self.graph.useSplines = 0
        self.graph.enabledLegend = 1

        #load settings
        self.loadSettings()

        #GUI
        self.tabs = OWGUI.tabWidget(self.controlArea)
        self.GeneralTab = OWGUI.createTabPage(self.tabs, "Main")
        self.SettingsTab = OWGUI.createTabPage(self.tabs, "Settings")

        self.createShowHiddenLists(self.GeneralTab, callback=self.updateGraph)
        self.connect(self.shownAttribsLB,
                     SIGNAL('itemDoubleClicked(QListWidgetItem*)'),
                     self.flipAttribute)

        self.optimizationDlg = ParallelOptimization(
            self, signalManager=self.signalManager)
        self.optimizationDlgButton = OWGUI.button(
            self.GeneralTab,
            self,
            "Optimization Dialog",
            callback=self.optimizationDlg.reshow,
            debuggingEnabled=0)

        self.zoomSelectToolbar = OWToolbars.ZoomSelectToolbar(
            self,
            self.GeneralTab,
            self.graph,
            self.autoSendSelection,
            buttons=(1, 2, 0, 7, 8))
        self.connect(self.zoomSelectToolbar.buttonSendSelections,
                     SIGNAL("clicked()"), self.sendSelections)

        #connect controls to appropriate functions
        self.connect(self.graphButton, SIGNAL("clicked()"),
                     self.graph.saveToFile)

        # ####################################
        # SETTINGS functionality
        box = OWGUI.widgetBox(self.SettingsTab, "Transparency")
        OWGUI.hSlider(box,
                      self,
                      'graph.alphaValue',
                      label="Examples: ",
                      minValue=0,
                      maxValue=255,
                      step=10,
                      callback=self.updateGraph,
                      tooltip="Alpha value used for drawing example lines")
        OWGUI.hSlider(
            box,
            self,
            'graph.alphaValue2',
            label="Rest:     ",
            minValue=0,
            maxValue=255,
            step=10,
            callback=self.updateGraph,
            tooltip="Alpha value used to draw statistics, example subsets, ..."
        )

        box = OWGUI.widgetBox(self.SettingsTab, "Jittering Options")
        OWGUI.comboBox(box,
                       self,
                       "graph.jitterSize",
                       label='Jittering size (% of size):  ',
                       orientation='horizontal',
                       callback=self.setJitteringSize,
                       items=self.jitterSizeNums,
                       sendSelectedValue=1,
                       valueType=float)

        # visual settings
        box = OWGUI.widgetBox(self.SettingsTab, "Visual Settings")

        OWGUI.checkBox(box,
                       self,
                       'graph.showAttrValues',
                       'Show attribute values',
                       callback=self.updateGraph)
        OWGUI.checkBox(box,
                       self,
                       'graph.useAntialiasing',
                       'Use antialiasing',
                       callback=self.updateGraph)
        OWGUI.checkBox(box,
                       self,
                       'graph.useSplines',
                       'Show splines',
                       callback=self.updateGraph,
                       tooltip="Show lines using splines")
        OWGUI.checkBox(box,
                       self,
                       'graph.enabledLegend',
                       'Show legend',
                       callback=self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Axis Distance")
        resizeColsBox = OWGUI.widgetBox(box, 0, "horizontal", 0)
        OWGUI.label(resizeColsBox, self, "Increase/decrease distance: ")
        b = OWGUI.toolButton(resizeColsBox,
                             self,
                             "+",
                             callback=self.increaseAxesDistance,
                             tooltip="Increase the distance between the axes",
                             width=30,
                             height=20)
        b = OWGUI.toolButton(resizeColsBox,
                             self,
                             "-",
                             callback=self.decreaseAxesDistance,
                             tooltip="Decrease the distance between the axes",
                             width=30,
                             height=20)
        OWGUI.rubber(resizeColsBox)
        OWGUI.checkBox(
            box,
            self,
            "graph.autoUpdateAxes",
            "Auto scale X axis",
            tooltip="Auto scale X axis to show all visualized attributes",
            callback=self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Statistical Information")
        OWGUI.comboBox(
            box,
            self,
            "graph.showStatistics",
            label="Statistics: ",
            orientation="horizontal",
            labelWidth=90,
            items=["No statistics", "Means, deviations", "Median, quartiles"],
            callback=self.updateGraph,
            sendSelectedValue=0,
            valueType=int)
        OWGUI.comboBox(
            box,
            self,
            "middleLabels",
            label="Middle labels: ",
            orientation="horizontal",
            labelWidth=90,
            items=["No labels", "Correlations", "VizRank"],
            callback=self.updateGraph,
            tooltip=
            "The information do you wish to view on top in the middle of coordinate axes",
            sendSelectedValue=1,
            valueType=str)
        OWGUI.checkBox(
            box,
            self,
            'graph.showDistributions',
            'Show distributions',
            callback=self.updateGraph,
            tooltip=
            "Show bars with distribution of class values (only for discrete attributes)"
        )

        box = OWGUI.widgetBox(self.SettingsTab,
                              "Colors",
                              orientation="horizontal")
        OWGUI.button(
            box,
            self,
            "Set colors",
            self.setColors,
            tooltip=
            "Set the canvas background color and color palette for coloring continuous variables",
            debuggingEnabled=0)

        box = OWGUI.widgetBox(self.SettingsTab,
                              "Auto Send Selected Data When...")
        OWGUI.checkBox(
            box,
            self,
            'autoSendSelection',
            'Adding/Removing selection areas',
            callback=self.selectionChanged,
            tooltip=
            "Send selected data whenever a selection area is added or removed")
        OWGUI.checkBox(
            box,
            self,
            'graph.sendSelectionOnUpdate',
            'Moving/Resizing selection areas',
            tooltip=
            "Send selected data when a user moves or resizes an existing selection area"
        )
        self.graph.autoSendSelectionCallback = self.selectionChanged

        self.SettingsTab.layout().addStretch(100)
        self.icons = self.createAttributeIconDict()

        dlg = self.createColorDialog()
        self.graph.contPalette = dlg.getContinuousPalette("contPalette")
        self.graph.discPalette = dlg.getDiscretePalette("discPalette")
        self.graph.setCanvasBackground(dlg.getColor("Canvas"))
        apply([
            self.zoomSelectToolbar.actionZooming,
            self.zoomSelectToolbar.actionRectangleSelection,
            self.zoomSelectToolbar.actionPolygonSelection
        ][self.toolbarSelection], [])
        self.cbShowAllAttributes()

        self.resize(900, 700)
    def __init__(self,parent=None, signalManager = None):
        OWWidget.__init__(self, parent, signalManager, "Parallel Coordinates", TRUE)

        #add a graph widget
        self.graph = OWParallelGraph(self, self.mainArea)
        self.mainArea.layout().addWidget(self.graph)

        self.showAllAttributes = 0

        self.inputs = [("Data", ExampleTable, self.setData, Default), ("Data Subset", ExampleTable, self.setSubsetData), ("Features", AttributeList, self.setShownAttributes)]
        self.outputs = [("Selected Data", ExampleTable), ("Other Data", ExampleTable), ("Features", AttributeList)]

        #set default settings
        self.data = None
        self.subsetData = None
        self.autoSendSelection = 1
        self.attrDiscOrder = "Unordered"
        self.attrContOrder = "Unordered"
        self.projections = None
        self.correlationDict = {}
        self.middleLabels = "Correlations"
        self.attributeSelectionList = None
        self.toolbarSelection = 0
        self.colorSettings = None
        self.selectedSchemaIndex = 0

        self.graph.jitterSize = 10
        self.graph.showDistributions = 1
        self.graph.showStatistics = 0
        self.graph.showAttrValues = 1
        self.graph.useSplines = 0
        self.graph.enabledLegend = 1

        #load settings
        self.loadSettings()

        #GUI
        self.tabs = OWGUI.tabWidget(self.controlArea)
        self.GeneralTab = OWGUI.createTabPage(self.tabs, "Main")
        self.SettingsTab = OWGUI.createTabPage(self.tabs, "Settings")

        self.createShowHiddenLists(self.GeneralTab, callback = self.updateGraph)
        self.connect(self.shownAttribsLB, SIGNAL('itemDoubleClicked(QListWidgetItem*)'), self.flipAttribute)

        self.optimizationDlg = ParallelOptimization(self, signalManager = self.signalManager)
        self.optimizationDlgButton = OWGUI.button(self.GeneralTab, self, "Optimization Dialog", callback = self.optimizationDlg.reshow, debuggingEnabled = 0)

        self.zoomSelectToolbar = OWToolbars.ZoomSelectToolbar(self, self.GeneralTab, self.graph, self.autoSendSelection, buttons = (1, 2, 0, 7, 8))
        self.connect(self.zoomSelectToolbar.buttonSendSelections, SIGNAL("clicked()"), self.sendSelections)

        #connect controls to appropriate functions
        self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)

        # ####################################
        # SETTINGS functionality
        box = OWGUI.widgetBox(self.SettingsTab, "Transparency")
        OWGUI.hSlider(box, self, 'graph.alphaValue', label = "Examples: ", minValue=0, maxValue=255, step=10, callback = self.updateGraph, tooltip = "Alpha value used for drawing example lines")
        OWGUI.hSlider(box, self, 'graph.alphaValue2', label = "Rest:     ", minValue=0, maxValue=255, step=10, callback = self.updateGraph, tooltip = "Alpha value used to draw statistics, example subsets, ...")

        box = OWGUI.widgetBox(self.SettingsTab, "Jittering Options")
        OWGUI.comboBox(box, self, "graph.jitterSize", label = 'Jittering size (% of size):  ', orientation='horizontal', callback = self.setJitteringSize, items = self.jitterSizeNums, sendSelectedValue = 1, valueType = float)

        # visual settings
        box = OWGUI.widgetBox(self.SettingsTab, "Visual Settings")

        OWGUI.checkBox(box, self, 'graph.showAttrValues', 'Show attribute values', callback = self.updateGraph)
        OWGUI.checkBox(box, self, 'graph.useAntialiasing', 'Use antialiasing', callback = self.updateGraph)
        OWGUI.checkBox(box, self, 'graph.useSplines', 'Show splines', callback = self.updateGraph, tooltip  = "Show lines using splines")
        OWGUI.checkBox(box, self, 'graph.enabledLegend', 'Show legend', callback = self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Axis Distance")
        resizeColsBox = OWGUI.widgetBox(box, 0, "horizontal", 0)
        OWGUI.label(resizeColsBox, self, "Increase/decrease distance: ")
        b = OWGUI.toolButton(resizeColsBox, self, "+", callback=self.increaseAxesDistance, tooltip = "Increase the distance between the axes", width=30, height = 20)
        b = OWGUI.toolButton(resizeColsBox, self, "-", callback=self.decreaseAxesDistance, tooltip = "Decrease the distance between the axes", width=30, height = 20)
        OWGUI.rubber(resizeColsBox)
        OWGUI.checkBox(box, self, "graph.autoUpdateAxes", "Auto scale X axis", tooltip = "Auto scale X axis to show all visualized attributes", callback = self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Statistical Information")
        OWGUI.comboBox(box, self, "graph.showStatistics", label = "Statistics: ", orientation = "horizontal", labelWidth=90, items = ["No statistics", "Means, deviations", "Median, quartiles"], callback = self.updateGraph, sendSelectedValue = 0, valueType = int)
        OWGUI.comboBox(box, self, "middleLabels", label = "Middle labels: ", orientation="horizontal", labelWidth=90, items = ["No labels", "Correlations", "VizRank"], callback = self.updateGraph, tooltip = "The information do you wish to view on top in the middle of coordinate axes", sendSelectedValue = 1, valueType = str)
        OWGUI.checkBox(box, self, 'graph.showDistributions', 'Show distributions', callback = self.updateGraph, tooltip = "Show bars with distribution of class values (only for discrete attributes)")

        box = OWGUI.widgetBox(self.SettingsTab, "Colors", orientation = "horizontal")
        OWGUI.button(box, self, "Set colors", self.setColors, tooltip = "Set the canvas background color and color palette for coloring continuous variables", debuggingEnabled = 0)

        box = OWGUI.widgetBox(self.SettingsTab, "Auto Send Selected Data When...")
        OWGUI.checkBox(box, self, 'autoSendSelection', 'Adding/Removing selection areas', callback = self.selectionChanged, tooltip = "Send selected data whenever a selection area is added or removed")
        OWGUI.checkBox(box, self, 'graph.sendSelectionOnUpdate', 'Moving/Resizing selection areas', tooltip = "Send selected data when a user moves or resizes an existing selection area")
        self.graph.autoSendSelectionCallback = self.selectionChanged

        self.SettingsTab.layout().addStretch(100)
        self.icons = self.createAttributeIconDict()

        dlg = self.createColorDialog()
        self.graph.contPalette = dlg.getContinuousPalette("contPalette")
        self.graph.discPalette = dlg.getDiscretePalette("discPalette")
        self.graph.setCanvasBackground(dlg.getColor("Canvas"))
        apply([self.zoomSelectToolbar.actionZooming, self.zoomSelectToolbar.actionRectangleSelection, self.zoomSelectToolbar.actionPolygonSelection][self.toolbarSelection], [])
        self.cbShowAllAttributes()

        self.resize(900, 700)
示例#3
0
class OWParallelCoordinates(OWVisWidget):
    settingsList = [
        "graph.jitterSize", "graph.showDistributions", "graph.showAttrValues",
        "graph.useAntialiasing", "graph.useSplines", "graph.alphaValue",
        "graph.alphaValue2", "graph.enabledLegend", "autoSendSelection",
        "toolbarSelection", "graph.showStatistics", "colorSettings",
        "selectedSchemaIndex", "showAllAttributes"
    ]
    jitterSizeNums = [0, 2, 5, 10, 15, 20, 30]
    contextHandlers = {
        "":
        DomainContextHandler("", [
            ContextField("shownAttributes",
                         DomainContextHandler.RequiredList,
                         selected="selectedShown",
                         reservoir="hiddenAttributes")
        ])
    }

    def __init__(self, parent=None, signalManager=None):
        OWWidget.__init__(self, parent, signalManager, "Parallel Coordinates",
                          TRUE)

        #add a graph widget
        self.graph = OWParallelGraph(self, self.mainArea)
        self.mainArea.layout().addWidget(self.graph)

        self.showAllAttributes = 0

        self.inputs = [("Data", ExampleTable, self.setData, Default),
                       ("Data Subset", ExampleTable, self.setSubsetData),
                       ("Features", AttributeList, self.setShownAttributes)]
        self.outputs = [("Selected Data", ExampleTable),
                        ("Other Data", ExampleTable),
                        ("Features", AttributeList)]

        #set default settings
        self.data = None
        self.subsetData = None
        self.autoSendSelection = 1
        self.attrDiscOrder = "Unordered"
        self.attrContOrder = "Unordered"
        self.projections = None
        self.correlationDict = {}
        self.middleLabels = "Correlations"
        self.attributeSelectionList = None
        self.toolbarSelection = 0
        self.colorSettings = None
        self.selectedSchemaIndex = 0

        self.graph.jitterSize = 10
        self.graph.showDistributions = 1
        self.graph.showStatistics = 0
        self.graph.showAttrValues = 1
        self.graph.useSplines = 0
        self.graph.enabledLegend = 1

        #load settings
        self.loadSettings()

        #GUI
        self.tabs = OWGUI.tabWidget(self.controlArea)
        self.GeneralTab = OWGUI.createTabPage(self.tabs, "Main")
        self.SettingsTab = OWGUI.createTabPage(self.tabs, "Settings")

        self.createShowHiddenLists(self.GeneralTab, callback=self.updateGraph)
        self.connect(self.shownAttribsLB,
                     SIGNAL('itemDoubleClicked(QListWidgetItem*)'),
                     self.flipAttribute)

        self.optimizationDlg = ParallelOptimization(
            self, signalManager=self.signalManager)
        self.optimizationDlgButton = OWGUI.button(
            self.GeneralTab,
            self,
            "Optimization Dialog",
            callback=self.optimizationDlg.reshow,
            debuggingEnabled=0)

        self.zoomSelectToolbar = OWToolbars.ZoomSelectToolbar(
            self,
            self.GeneralTab,
            self.graph,
            self.autoSendSelection,
            buttons=(1, 2, 0, 7, 8))
        self.connect(self.zoomSelectToolbar.buttonSendSelections,
                     SIGNAL("clicked()"), self.sendSelections)

        #connect controls to appropriate functions
        self.connect(self.graphButton, SIGNAL("clicked()"),
                     self.graph.saveToFile)

        # ####################################
        # SETTINGS functionality
        box = OWGUI.widgetBox(self.SettingsTab, "Transparency")
        OWGUI.hSlider(box,
                      self,
                      'graph.alphaValue',
                      label="Examples: ",
                      minValue=0,
                      maxValue=255,
                      step=10,
                      callback=self.updateGraph,
                      tooltip="Alpha value used for drawing example lines")
        OWGUI.hSlider(
            box,
            self,
            'graph.alphaValue2',
            label="Rest:     ",
            minValue=0,
            maxValue=255,
            step=10,
            callback=self.updateGraph,
            tooltip="Alpha value used to draw statistics, example subsets, ..."
        )

        box = OWGUI.widgetBox(self.SettingsTab, "Jittering Options")
        OWGUI.comboBox(box,
                       self,
                       "graph.jitterSize",
                       label='Jittering size (% of size):  ',
                       orientation='horizontal',
                       callback=self.setJitteringSize,
                       items=self.jitterSizeNums,
                       sendSelectedValue=1,
                       valueType=float)

        # visual settings
        box = OWGUI.widgetBox(self.SettingsTab, "Visual Settings")

        OWGUI.checkBox(box,
                       self,
                       'graph.showAttrValues',
                       'Show attribute values',
                       callback=self.updateGraph)
        OWGUI.checkBox(box,
                       self,
                       'graph.useAntialiasing',
                       'Use antialiasing',
                       callback=self.updateGraph)
        OWGUI.checkBox(box,
                       self,
                       'graph.useSplines',
                       'Show splines',
                       callback=self.updateGraph,
                       tooltip="Show lines using splines")
        OWGUI.checkBox(box,
                       self,
                       'graph.enabledLegend',
                       'Show legend',
                       callback=self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Axis Distance")
        resizeColsBox = OWGUI.widgetBox(box, 0, "horizontal", 0)
        OWGUI.label(resizeColsBox, self, "Increase/decrease distance: ")
        b = OWGUI.toolButton(resizeColsBox,
                             self,
                             "+",
                             callback=self.increaseAxesDistance,
                             tooltip="Increase the distance between the axes",
                             width=30,
                             height=20)
        b = OWGUI.toolButton(resizeColsBox,
                             self,
                             "-",
                             callback=self.decreaseAxesDistance,
                             tooltip="Decrease the distance between the axes",
                             width=30,
                             height=20)
        OWGUI.rubber(resizeColsBox)
        OWGUI.checkBox(
            box,
            self,
            "graph.autoUpdateAxes",
            "Auto scale X axis",
            tooltip="Auto scale X axis to show all visualized attributes",
            callback=self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Statistical Information")
        OWGUI.comboBox(
            box,
            self,
            "graph.showStatistics",
            label="Statistics: ",
            orientation="horizontal",
            labelWidth=90,
            items=["No statistics", "Means, deviations", "Median, quartiles"],
            callback=self.updateGraph,
            sendSelectedValue=0,
            valueType=int)
        OWGUI.comboBox(
            box,
            self,
            "middleLabels",
            label="Middle labels: ",
            orientation="horizontal",
            labelWidth=90,
            items=["No labels", "Correlations", "VizRank"],
            callback=self.updateGraph,
            tooltip=
            "The information do you wish to view on top in the middle of coordinate axes",
            sendSelectedValue=1,
            valueType=str)
        OWGUI.checkBox(
            box,
            self,
            'graph.showDistributions',
            'Show distributions',
            callback=self.updateGraph,
            tooltip=
            "Show bars with distribution of class values (only for discrete attributes)"
        )

        box = OWGUI.widgetBox(self.SettingsTab,
                              "Colors",
                              orientation="horizontal")
        OWGUI.button(
            box,
            self,
            "Set colors",
            self.setColors,
            tooltip=
            "Set the canvas background color and color palette for coloring continuous variables",
            debuggingEnabled=0)

        box = OWGUI.widgetBox(self.SettingsTab,
                              "Auto Send Selected Data When...")
        OWGUI.checkBox(
            box,
            self,
            'autoSendSelection',
            'Adding/Removing selection areas',
            callback=self.selectionChanged,
            tooltip=
            "Send selected data whenever a selection area is added or removed")
        OWGUI.checkBox(
            box,
            self,
            'graph.sendSelectionOnUpdate',
            'Moving/Resizing selection areas',
            tooltip=
            "Send selected data when a user moves or resizes an existing selection area"
        )
        self.graph.autoSendSelectionCallback = self.selectionChanged

        self.SettingsTab.layout().addStretch(100)
        self.icons = self.createAttributeIconDict()

        dlg = self.createColorDialog()
        self.graph.contPalette = dlg.getContinuousPalette("contPalette")
        self.graph.discPalette = dlg.getDiscretePalette("discPalette")
        self.graph.setCanvasBackground(dlg.getColor("Canvas"))
        apply([
            self.zoomSelectToolbar.actionZooming,
            self.zoomSelectToolbar.actionRectangleSelection,
            self.zoomSelectToolbar.actionPolygonSelection
        ][self.toolbarSelection], [])
        self.cbShowAllAttributes()

        self.resize(900, 700)

    def flipAttribute(self, item):
        if self.graph.flipAttribute(str(item.text())):
            self.updateGraph()
            self.information(0)
        else:
            self.information(
                0,
                "Didn't flip the attribute. To flip a continuous attribute uncheck 'Global value scaling' checkbox."
            )

    def updateGraph(self, *args):
        attrs = self.getShownAttributeList()
        self.graph.updateData(attrs, self.buildMidLabels(attrs))

    def increaseAxesDistance(self):
        m = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().minValue()
        M = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().maxValue()
        if (M - m) == 0:
            return  # we have not yet updated the axes (self.graph.updateAxes())
        self.graph.setAxisScale(QwtPlot.xBottom, m, M - (M - m) / 10., 1)
        self.graph.replot()

    def decreaseAxesDistance(self):
        m = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().minValue()
        M = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().maxValue()
        if (M - m) == 0:
            return  # we have not yet updated the axes (self.graph.updateAxes())

        self.graph.setAxisScale(
            QwtPlot.xBottom, m,
            min(len(self.graph.visualizedAttributes) - 1, M + (M - m) / 10.),
            1)
        self.graph.replot()

    # build a list of strings that will be shown in the middle of the parallel axis
    def buildMidLabels(self, attrs):
        labels = []
        if self.middleLabels == "No labels" or not self.graph.haveData:
            return None
        elif self.middleLabels == "Correlations":
            for i in range(len(attrs) - 1):
                corr = None
                if self.correlationDict.has_key((attrs[i], attrs[i + 1])):
                    corr = self.correlationDict[(attrs[i], attrs[i + 1])]
                elif self.correlationDict.has_key((attrs[i + 1], attrs[i])):
                    corr = self.correlationDict[(attrs[i + 1], attrs[i])]
                else:
                    try:
                        corr = orngVisFuncts.computeCorrelation(
                            self.graph.rawData, attrs[i], attrs[i + 1])
                    except:
                        corr = None
                    self.correlationDict[(attrs[i], attrs[i + 1])] = corr
                if corr and (self.graph.attributeFlipInfo.get(attrs[i], 0)
                             != self.graph.attributeFlipInfo.get(
                                 attrs[i + 1], 0)):
                    corr = -corr
                if corr: labels.append("%2.3f" % (corr))
                else: labels.append("")
        elif self.middleLabels == "VizRank":
            for i in range(len(attrs) - 1):
                val = self.optimizationDlg.getVizRankVal(
                    attrs[i], attrs[i + 1])
                if val: labels.append("%2.2f%%" % (val))
                else: labels.append("")
        return labels

    # ------------- SIGNALS --------------------------
    # receive new data and update all fields
    def setData(self, data):
        if data and (len(data) == 0 or len(data.domain) == 0):
            data = None
        if self.data != None and data != None and self.data.checksum(
        ) == data.checksum():
            return  # check if the new data set is the same as the old one

        self.closeContext()
        sameDomain = self.data and data and data.domain.checksum(
        ) == self.data.domain.checksum(
        )  # preserve attribute choice if the domain is the same
        self.projections = None
        self.correlationDict = {}
        self.data = data
        self.optimizationDlg.clearResults()
        if not sameDomain:
            self.setShownAttributeList(self.attributeSelectionList)
        self.openContext("", self.data)
        self.resetAttrManipulation()

    def setSubsetData(self, subData):
        self.subsetData = subData

    # attribute selection signal - list of attributes to show
    def setShownAttributes(self, attributeSelectionList):
        self.attributeSelectionList = attributeSelectionList

    # this is called by OWBaseWidget after setData and setSubsetData are called. this way the graph is updated only once
    def handleNewSignals(self):
        self.graph.setData(self.data, self.subsetData)
        if self.attributeSelectionList and 0 not in [
                self.graph.attributeNameIndex.has_key(attr)
                for attr in self.attributeSelectionList
        ]:
            self.setShownAttributeList(self.attributeSelectionList)
        else:
            self.setShownAttributeList()
        self.attributeSelectionList = None
        self.updateGraph()
        self.sendSelections()

    def sendShownAttributes(self, attrList=None):
        if attrList == None:
            attrList = self.getShownAttributeList()
        self.send("Features", attrList)

    def selectionChanged(self):
        self.zoomSelectToolbar.buttonSendSelections.setEnabled(
            not self.autoSendSelection)
        if self.autoSendSelection:
            self.sendSelections()

    # send signals with selected and unselected examples as two datasets
    def sendSelections(self):
        (selected, unselected) = self.graph.getSelectionsAsExampleTables()
        self.send("Selected Data", selected)
        self.send("Other Data", unselected)

    # jittering options
    def setJitteringSize(self):
        self.graph.rescaleData()
        self.updateGraph()

    def setColors(self):
        dlg = self.createColorDialog()
        if dlg.exec_():
            self.colorSettings = dlg.getColorSchemas()
            self.selectedSchemaIndex = dlg.selectedSchemaIndex
            self.graph.contPalette = dlg.getContinuousPalette("contPalette")
            self.graph.discPalette = dlg.getDiscretePalette("discPalette")
            self.graph.setCanvasBackground(dlg.getColor("Canvas"))
            self.updateGraph()

    def createColorDialog(self):
        c = OWColorPalette.ColorPaletteDlg(self, "Color Palette")
        c.createDiscretePalette("discPalette", "Discrete Palette")
        c.createContinuousPalette("contPalette", "Continuous Palette")
        box = c.createBox("otherColors", "Other Colors")
        c.createColorButton(box, "Canvas", "Canvas color", QColor(Qt.white))
        c.setColorSchemas(self.colorSettings, self.selectedSchemaIndex)
        return c

    def saveSettings(self):
        OWWidget.saveSettings(self)
        self.optimizationDlg.saveSettings()

    def closeEvent(self, ce):
        self.optimizationDlg.hide()
        OWWidget.closeEvent(self, ce)

    def sendReport(self):
        self.reportImage(self.graph.saveToFileDirect, QSize(500, 500))
class OWParallelCoordinates(OWVisWidget):
    settingsList = ["graph.jitterSize", "graph.showDistributions",
                    "graph.showAttrValues", "graph.useAntialiasing",
                    "graph.useSplines", "graph.alphaValue", "graph.alphaValue2", "graph.enabledLegend", "autoSendSelection",
                    "toolbarSelection", "graph.showStatistics", "colorSettings", "selectedSchemaIndex", "showAllAttributes"]
    jitterSizeNums = [0, 2,  5,  10, 15, 20, 30]
    contextHandlers = {"": DomainContextHandler("", [ContextField("shownAttributes", DomainContextHandler.RequiredList, selected="selectedShown", reservoir="hiddenAttributes")])}

    def __init__(self,parent=None, signalManager = None):
        OWWidget.__init__(self, parent, signalManager, "Parallel Coordinates", TRUE)

        #add a graph widget
        self.graph = OWParallelGraph(self, self.mainArea)
        self.mainArea.layout().addWidget(self.graph)

        self.showAllAttributes = 0

        self.inputs = [("Data", ExampleTable, self.setData, Default), ("Data Subset", ExampleTable, self.setSubsetData), ("Features", AttributeList, self.setShownAttributes)]
        self.outputs = [("Selected Data", ExampleTable), ("Other Data", ExampleTable), ("Features", AttributeList)]

        #set default settings
        self.data = None
        self.subsetData = None
        self.autoSendSelection = 1
        self.attrDiscOrder = "Unordered"
        self.attrContOrder = "Unordered"
        self.projections = None
        self.correlationDict = {}
        self.middleLabels = "Correlations"
        self.attributeSelectionList = None
        self.toolbarSelection = 0
        self.colorSettings = None
        self.selectedSchemaIndex = 0

        self.graph.jitterSize = 10
        self.graph.showDistributions = 1
        self.graph.showStatistics = 0
        self.graph.showAttrValues = 1
        self.graph.useSplines = 0
        self.graph.enabledLegend = 1

        #load settings
        self.loadSettings()

        #GUI
        self.tabs = OWGUI.tabWidget(self.controlArea)
        self.GeneralTab = OWGUI.createTabPage(self.tabs, "Main")
        self.SettingsTab = OWGUI.createTabPage(self.tabs, "Settings")

        self.createShowHiddenLists(self.GeneralTab, callback = self.updateGraph)
        self.connect(self.shownAttribsLB, SIGNAL('itemDoubleClicked(QListWidgetItem*)'), self.flipAttribute)

        self.optimizationDlg = ParallelOptimization(self, signalManager = self.signalManager)
        self.optimizationDlgButton = OWGUI.button(self.GeneralTab, self, "Optimization Dialog", callback = self.optimizationDlg.reshow, debuggingEnabled = 0)

        self.zoomSelectToolbar = OWToolbars.ZoomSelectToolbar(self, self.GeneralTab, self.graph, self.autoSendSelection, buttons = (1, 2, 0, 7, 8))
        self.connect(self.zoomSelectToolbar.buttonSendSelections, SIGNAL("clicked()"), self.sendSelections)

        #connect controls to appropriate functions
        self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)

        # ####################################
        # SETTINGS functionality
        box = OWGUI.widgetBox(self.SettingsTab, "Transparency")
        OWGUI.hSlider(box, self, 'graph.alphaValue', label = "Examples: ", minValue=0, maxValue=255, step=10, callback = self.updateGraph, tooltip = "Alpha value used for drawing example lines")
        OWGUI.hSlider(box, self, 'graph.alphaValue2', label = "Rest:     ", minValue=0, maxValue=255, step=10, callback = self.updateGraph, tooltip = "Alpha value used to draw statistics, example subsets, ...")

        box = OWGUI.widgetBox(self.SettingsTab, "Jittering Options")
        OWGUI.comboBox(box, self, "graph.jitterSize", label = 'Jittering size (% of size):  ', orientation='horizontal', callback = self.setJitteringSize, items = self.jitterSizeNums, sendSelectedValue = 1, valueType = float)

        # visual settings
        box = OWGUI.widgetBox(self.SettingsTab, "Visual Settings")

        OWGUI.checkBox(box, self, 'graph.showAttrValues', 'Show attribute values', callback = self.updateGraph)
        OWGUI.checkBox(box, self, 'graph.useAntialiasing', 'Use antialiasing', callback = self.updateGraph)
        OWGUI.checkBox(box, self, 'graph.useSplines', 'Show splines', callback = self.updateGraph, tooltip  = "Show lines using splines")
        OWGUI.checkBox(box, self, 'graph.enabledLegend', 'Show legend', callback = self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Axis Distance")
        resizeColsBox = OWGUI.widgetBox(box, 0, "horizontal", 0)
        OWGUI.label(resizeColsBox, self, "Increase/decrease distance: ")
        b = OWGUI.toolButton(resizeColsBox, self, "+", callback=self.increaseAxesDistance, tooltip = "Increase the distance between the axes", width=30, height = 20)
        b = OWGUI.toolButton(resizeColsBox, self, "-", callback=self.decreaseAxesDistance, tooltip = "Decrease the distance between the axes", width=30, height = 20)
        OWGUI.rubber(resizeColsBox)
        OWGUI.checkBox(box, self, "graph.autoUpdateAxes", "Auto scale X axis", tooltip = "Auto scale X axis to show all visualized attributes", callback = self.updateGraph)

        box = OWGUI.widgetBox(self.SettingsTab, "Statistical Information")
        OWGUI.comboBox(box, self, "graph.showStatistics", label = "Statistics: ", orientation = "horizontal", labelWidth=90, items = ["No statistics", "Means, deviations", "Median, quartiles"], callback = self.updateGraph, sendSelectedValue = 0, valueType = int)
        OWGUI.comboBox(box, self, "middleLabels", label = "Middle labels: ", orientation="horizontal", labelWidth=90, items = ["No labels", "Correlations", "VizRank"], callback = self.updateGraph, tooltip = "The information do you wish to view on top in the middle of coordinate axes", sendSelectedValue = 1, valueType = str)
        OWGUI.checkBox(box, self, 'graph.showDistributions', 'Show distributions', callback = self.updateGraph, tooltip = "Show bars with distribution of class values (only for discrete attributes)")

        box = OWGUI.widgetBox(self.SettingsTab, "Colors", orientation = "horizontal")
        OWGUI.button(box, self, "Set colors", self.setColors, tooltip = "Set the canvas background color and color palette for coloring continuous variables", debuggingEnabled = 0)

        box = OWGUI.widgetBox(self.SettingsTab, "Auto Send Selected Data When...")
        OWGUI.checkBox(box, self, 'autoSendSelection', 'Adding/Removing selection areas', callback = self.selectionChanged, tooltip = "Send selected data whenever a selection area is added or removed")
        OWGUI.checkBox(box, self, 'graph.sendSelectionOnUpdate', 'Moving/Resizing selection areas', tooltip = "Send selected data when a user moves or resizes an existing selection area")
        self.graph.autoSendSelectionCallback = self.selectionChanged

        self.SettingsTab.layout().addStretch(100)
        self.icons = self.createAttributeIconDict()

        dlg = self.createColorDialog()
        self.graph.contPalette = dlg.getContinuousPalette("contPalette")
        self.graph.discPalette = dlg.getDiscretePalette("discPalette")
        self.graph.setCanvasBackground(dlg.getColor("Canvas"))
        apply([self.zoomSelectToolbar.actionZooming, self.zoomSelectToolbar.actionRectangleSelection, self.zoomSelectToolbar.actionPolygonSelection][self.toolbarSelection], [])
        self.cbShowAllAttributes()

        self.resize(900, 700)

    def flipAttribute(self, item):
        if self.graph.flipAttribute(str(item.text())):
            self.updateGraph()
            self.information(0)
        else:
            self.information(0, "Didn't flip the attribute. To flip a continuous attribute uncheck 'Global value scaling' checkbox.")

    def updateGraph(self, *args):
        attrs = self.getShownAttributeList()
        self.graph.updateData(attrs, self.buildMidLabels(attrs))


    def increaseAxesDistance(self):
        m = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().minValue()
        M = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().maxValue()
        if (M-m) == 0:
            return      # we have not yet updated the axes (self.graph.updateAxes())
        self.graph.setAxisScale(QwtPlot.xBottom, m, M - (M-m)/10., 1)
        self.graph.replot()

    def decreaseAxesDistance(self):
        m = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().minValue()
        M = self.graph.axisScaleDiv(QwtPlot.xBottom).interval().maxValue()
        if (M-m) == 0:
            return      # we have not yet updated the axes (self.graph.updateAxes())

        self.graph.setAxisScale(QwtPlot.xBottom, m, min(len(self.graph.visualizedAttributes)-1, M + (M-m)/10.), 1)
        self.graph.replot()


    # build a list of strings that will be shown in the middle of the parallel axis
    def buildMidLabels(self, attrs):
        labels = []
        if self.middleLabels == "No labels" or not self.graph.haveData: return None
        elif self.middleLabels == "Correlations":
            for i in range(len(attrs)-1):
                corr = None
                if self.correlationDict.has_key((attrs[i], attrs[i+1])):   corr = self.correlationDict[(attrs[i], attrs[i+1])]
                elif self.correlationDict.has_key((attrs[i+1], attrs[i])): corr = self.correlationDict[(attrs[i+1], attrs[i])]
                else:
                    try:
                        corr = orngVisFuncts.computeCorrelation(self.graph.rawData, attrs[i], attrs[i+1])
                    except:
                        corr = None
                    self.correlationDict[(attrs[i], attrs[i+1])] = corr
                if corr and (self.graph.attributeFlipInfo.get(attrs[i], 0) != self.graph.attributeFlipInfo.get(attrs[i+1], 0)): corr = -corr
                if corr: labels.append("%2.3f" % (corr))
                else: labels.append("")
        elif self.middleLabels == "VizRank":
            for i in range(len(attrs)-1):
                val = self.optimizationDlg.getVizRankVal(attrs[i], attrs[i+1])
                if val: labels.append("%2.2f%%" % (val))
                else: labels.append("")
        return labels


    # ------------- SIGNALS --------------------------
    # receive new data and update all fields
    def setData(self, data):
        if data and (len(data) == 0 or len(data.domain) == 0):
            data = None
        if self.data != None and data != None and self.data.checksum() == data.checksum():
            return    # check if the new data set is the same as the old one

        self.closeContext()
        sameDomain = self.data and data and data.domain.checksum() == self.data.domain.checksum() # preserve attribute choice if the domain is the same
        self.projections = None
        self.correlationDict = {}
        self.data = data
        self.optimizationDlg.clearResults()
        if not sameDomain:
            self.setShownAttributeList(self.attributeSelectionList)
        self.openContext("", self.data)
        self.resetAttrManipulation()


    def setSubsetData(self, subData):
        self.subsetData = subData


    # attribute selection signal - list of attributes to show
    def setShownAttributes(self, attributeSelectionList):
        self.attributeSelectionList = attributeSelectionList


    # this is called by OWBaseWidget after setData and setSubsetData are called. this way the graph is updated only once
    def handleNewSignals(self):
        self.graph.setData(self.data, self.subsetData)
        if self.attributeSelectionList and 0 not in [self.graph.attributeNameIndex.has_key(attr) for attr in self.attributeSelectionList]:
            self.setShownAttributeList(self.attributeSelectionList)
        else:
            self.setShownAttributeList()
        self.attributeSelectionList = None
        self.updateGraph()
        self.sendSelections()


    def sendShownAttributes(self, attrList = None):
        if attrList == None:
            attrList = self.getShownAttributeList()
        self.send("Features", attrList)

    def selectionChanged(self):
        self.zoomSelectToolbar.buttonSendSelections.setEnabled(not self.autoSendSelection)
        if self.autoSendSelection:
            self.sendSelections()

    # send signals with selected and unselected examples as two datasets
    def sendSelections(self):
        (selected, unselected) = self.graph.getSelectionsAsExampleTables()
        self.send("Selected Data", selected)
        self.send("Other Data", unselected)


    # jittering options
    def setJitteringSize(self):
        self.graph.rescaleData()
        self.updateGraph()

    def setColors(self):
        dlg = self.createColorDialog()
        if dlg.exec_():
            self.colorSettings = dlg.getColorSchemas()
            self.selectedSchemaIndex = dlg.selectedSchemaIndex
            self.graph.contPalette = dlg.getContinuousPalette("contPalette")
            self.graph.discPalette = dlg.getDiscretePalette("discPalette")
            self.graph.setCanvasBackground(dlg.getColor("Canvas"))
            self.updateGraph()

    def createColorDialog(self):
        c = OWColorPalette.ColorPaletteDlg(self, "Color Palette")
        c.createDiscretePalette("discPalette", "Discrete Palette")
        c.createContinuousPalette("contPalette", "Continuous Palette")
        box = c.createBox("otherColors", "Other Colors")
        c.createColorButton(box, "Canvas", "Canvas color", QColor(Qt.white))
        c.setColorSchemas(self.colorSettings, self.selectedSchemaIndex)
        return c

    def saveSettings(self):
        OWWidget.saveSettings(self)
        self.optimizationDlg.saveSettings()

    def closeEvent(self, ce):
        self.optimizationDlg.hide()
        OWWidget.closeEvent(self, ce)

    def sendReport(self):
        self.reportImage(self.graph.saveToFileDirect, QSize(500, 500))