def plot(self, profile):
        if len(profile.profileDict) <= 0:
            self.emptyAxis()
            return

        if len(profile.profileDict) > 1000:
            QtGui.QApplication.instance().setOverrideCursor(
                QtGui.QCursor(QtCore.Qt.ArrowCursor))
            reply = QtGui.QMessageBox.question(
                self, 'Continue?', 'Profile contains ' +
                str(len(profile.profileDict)) + ' features. ' +
                'It may take several seconds to generate this plot. Exploring the data at a higher hierarchy level is recommended. '
                + 'Do you wish to continue?', QtGui.QMessageBox.Yes,
                QtGui.QMessageBox.No)
            QtGui.QApplication.instance().restoreOverrideCursor()
            if reply == QtGui.QMessageBox.No:
                self.emptyAxis()
                return

        # *** Colour of plot elements
        profile1Colour = str(self.preferences['Sample 1 colour'].name())
        profile2Colour = str(self.preferences['Sample 2 colour'].name())

        # *** Set sample names
        if self.sampleName1 == '' and self.sampleName2 == '':
            self.sampleName1 = profile.sampleNames[0]
            self.sampleName2 = profile.sampleNames[1]

        # *** Create lists for each quantity of interest and calculate CIs
        wilsonCI = WilsonCI()
        zCoverage = inverseNormalCDF(0.95)
        confInter1 = []
        confInter2 = []

        tables = profile.getLabeledTables()
        features = []
        field1 = []
        field2 = []
        for table in tables:
            feature, seq1, seq2, parentSeq1, parentSeq2 = table
            features.append(feature)
            field1.append(float(seq1) * 100 / max(parentSeq1, 1))
            field2.append(float(seq2) * 100 / max(parentSeq2, 1))

            if self.bShowCIs:
                lowerCI, upperCI, p = wilsonCI.run(seq1, parentSeq1, 0.95,
                                                   zCoverage)
                confInter1.append(
                    [max(lowerCI * 100, 0),
                     min(upperCI * 100, 100)])

                lowerCI, upperCI, p = wilsonCI.run(seq2, parentSeq2, 0.95,
                                                   zCoverage)
                confInter2.append(
                    [max(lowerCI * 100, 0),
                     min(upperCI * 100, 100)])

        # *** Set figure size
        self.fig.clear()
        self.fig.set_size_inches(self.figWidth, self.figHeight)

        if self.bShowHistograms:
            histogramSizeX = self.histogramSize / self.figWidth
            histogramSizeY = self.histogramSize / self.figHeight
        else:
            histogramSizeX = 0.0
            histogramSizeY = 0.0

        padding = 0.1  # inches
        xOffsetFigSpace = (0.4 + padding) / self.figWidth
        yOffsetFigSpace = (0.3 + padding) / self.figHeight
        axesScatter = self.fig.add_axes([
            xOffsetFigSpace, yOffsetFigSpace, 1.0 - xOffsetFigSpace -
            histogramSizeX - (2 * padding) / self.figWidth, 1.0 -
            yOffsetFigSpace - histogramSizeY - (2 * padding) / self.figHeight
        ])

        if self.bShowHistograms:
            axesTopHistogram = self.fig.add_axes([
                xOffsetFigSpace,
                1.0 - histogramSizeY - padding / self.figHeight,
                1.0 - xOffsetFigSpace - histogramSizeX -
                (2 * padding) / self.figWidth, histogramSizeY
            ])

            axesRightHistogram = self.fig.add_axes([
                1.0 - histogramSizeX - padding / self.figWidth,
                yOffsetFigSpace, histogramSizeX, 1.0 - yOffsetFigSpace -
                histogramSizeY - (2 * padding) / self.figHeight
            ])

        # *** Handle mouse events
        tooltips = []
        for i in xrange(0, len(field1)):
            tooltip = features[i] + '\n\n'
            tooltip += 'Sequences in ' + self.sampleName1 + ': ' + str(
                tables[i][1]) + '\n'
            tooltip += 'Sequences in ' + self.sampleName2 + ': ' + str(
                tables[i][2]) + '\n\n'
            tooltip += (self.sampleName1 +
                        ' percentage: %.3f' % field1[i]) + '\n'
            tooltip += (self.sampleName2 +
                        ' percentage: %.3f' % field2[i]) + '\n\n'
            tooltip += 'Difference between proportions (%): ' + (
                '%.3f' % (field1[i] - field2[i])) + '\n'

            if field2[i] != 0:
                tooltip += 'Ratio of proportions: %.3f' % (field1[i] /
                                                           field2[i])
            else:
                tooltip += 'Ratio of proportions: undefined'
            tooltips.append(tooltip)

        self.plotEventHandler = PlotEventHandler(field1, field2, tooltips)

        self.mouseEventCallback(self.plotEventHandler)

        # *** Plot data

        # set visual properties of all points
        colours = []
        highlightedField1 = []
        highlightedField2 = []
        highlighColours = []
        for i in xrange(0, len(field1)):
            if field1[i] > field2[i]:
                colours.append(profile1Colour)
            else:
                colours.append(profile2Colour)

            if features[i] in self.preferences[
                    'Selected exploratory features']:
                highlightedField1.append(field1[i])
                highlightedField2.append(field2[i])
                highlighColours.append(colours[i])

        # scatter plot
        axesScatter.scatter(field1, field2, c=colours, zorder=5)
        if len(highlightedField1) > 0:
            axesScatter.scatter(highlightedField1,
                                highlightedField2,
                                c=highlighColours,
                                edgecolors='red',
                                linewidth=2,
                                zorder=10)

        # plot CIs
        if self.bShowCIs:
            ciLinesX = [
                Line2D([confInter1[i][0], confInter1[i][1]],
                       [field2[i], field2[i]],
                       color='black') for i in xrange(0, len(field1))
            ]
            ciLinesY = [
                Line2D([field1[i], field1[i]],
                       [confInter2[i][0], confInter2[i][1]],
                       color='black') for i in xrange(0, len(field1))
            ]

            for i in xrange(0, len(ciLinesX)):
                e = ciLinesX[i]
                axesScatter.add_artist(e)
                e.set_clip_box(axesScatter.bbox)

            for i in xrange(0, len(ciLinesY)):
                e = ciLinesY[i]
                axesScatter.add_artist(e)
                e.set_clip_box(axesScatter.bbox)

        # plot y=x line
        maxProportion = max(max(field1), max(field2)) * 1.05
        axesScatter.plot([0, maxProportion], [0, maxProportion],
                         color='gray',
                         linestyle='dashed',
                         marker='',
                         zorder=1)

        axesScatter.set_xlabel(self.sampleName1 + ' (%)', fontsize=8)
        axesScatter.set_ylabel(self.sampleName2 + ' (%)', fontsize=8)

        axesScatter.set_xlim(0, maxProportion)
        axesScatter.set_ylim(0, maxProportion)

        # *** Prettify scatter plot
        for label in axesScatter.get_xticklabels():
            label.set_size(8)

        for label in axesScatter.get_yticklabels():
            label.set_size(8)

        # plot histograms
        if self.bShowHistograms:
            # plot top histogram
            axesTopHistogram.xaxis.set_major_formatter(NullFormatter())
            pdf, bins, patches = axesTopHistogram.hist(
                field1, bins=self.numBins, facecolor=profile1Colour)
            axesTopHistogram.set_xlim(axesScatter.get_xlim())
            axesTopHistogram.set_yticks([0, max(pdf)])

            # plot right histogram
            axesRightHistogram.yaxis.set_major_formatter(NullFormatter())
            pdf, bins, patches = axesRightHistogram.hist(
                field2,
                bins=self.numBins,
                orientation='horizontal',
                facecolor=profile2Colour)
            axesRightHistogram.set_ylim(axesScatter.get_ylim())
            axesRightHistogram.set_xticks([0, max(pdf)])

            # *** Prettify histogram plot
            for label in axesTopHistogram.get_xticklabels():
                label.set_size(8)

            for label in axesTopHistogram.get_yticklabels():
                label.set_size(8)

            for label in axesRightHistogram.get_xticklabels():
                label.set_size(8)

            for label in axesRightHistogram.get_yticklabels():
                label.set_size(8)

            for a in axesTopHistogram.yaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for a in axesTopHistogram.xaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for loc, spine in axesTopHistogram.spines.iteritems():
                if loc in ['right', 'top']:
                    spine.set_color('none')

            for a in axesRightHistogram.yaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for a in axesRightHistogram.xaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for loc, spine in axesRightHistogram.spines.iteritems():
                if loc in ['right', 'top']:
                    spine.set_color('none')

        self.updateGeometry()
        self.draw()
Beispiel #2
0
    def plot(self, profile):
        if len(profile.profileDict) <= 0:
            self.emptyAxis()
            return

        if len(profile.profileDict) > 200:
            QtGui.QApplication.instance().setOverrideCursor(
                QtGui.QCursor(QtCore.Qt.ArrowCursor))
            reply = QtGui.QMessageBox.question(
                self, 'Continue?', 'Profile contains ' +
                str(len(profile.profileDict)) + ' features. ' +
                'It may take several seconds to generate this plot. Exploring the data at a higher hierarchy level is recommended. '
                + 'Do you wish to continue?', QtGui.QMessageBox.Yes,
                QtGui.QMessageBox.No)
            QtGui.QApplication.instance().restoreOverrideCursor()
            if reply == QtGui.QMessageBox.No:
                self.emptyAxis()
                return

        # *** Colour of plot elements
        profile1Colour = str(self.preferences['Sample 1 colour'].name())
        profile2Colour = str(self.preferences['Sample 2 colour'].name())

        # *** Set sample names
        if self.sampleName1 == '' and self.sampleName2 == '':
            self.sampleName1 = profile.sampleNames[0]
            self.sampleName2 = profile.sampleNames[1]

        # *** Create lists for each quantity of interest and calculate CIs
        wilsonCI = WilsonCI()
        zCoverage = inverseNormalCDF(0.95)
        confInter1 = []
        confInter2 = []

        tables = profile.getLabeledTables()
        features = []
        field1 = []
        field2 = []
        if self.fieldToPlot == 'Number of sequences':
            for table in tables:
                feature, seq1, seq2, parentSeq1, parentSeq2 = table
                features.append(feature)
                field1.append(seq1)
                field2.append(seq2)

                if self.bShowCIs:
                    lowerCI, upperCI, p = wilsonCI.run(seq1, parentSeq1, 0.95,
                                                       zCoverage)
                    confInter1.append(max((p - lowerCI) * parentSeq1, 0))

                    lowerCI, upperCI, p = wilsonCI.run(seq2, parentSeq2, 0.95,
                                                       zCoverage)
                    confInter2.append(max((p - lowerCI) * parentSeq2, 0))
                else:
                    confInter1.append(0)
                    confInter2.append(0)

        elif self.fieldToPlot == 'Proportion of sequences':
            for table in tables:
                feature, seq1, seq2, parentSeq1, parentSeq2 = table
                features.append(feature)
                field1.append(float(seq1) * 100 / max(parentSeq1, 1))
                field2.append(float(seq2) * 100 / max(parentSeq2, 1))

                if self.bShowCIs:
                    lowerCI, upperCI, p = wilsonCI.run(seq1, parentSeq1, 0.95,
                                                       zCoverage)
                    confInter1.append(max((p - lowerCI) * 100, 0))

                    lowerCI, upperCI, p = wilsonCI.run(seq2, parentSeq2, 0.95,
                                                       zCoverage)
                    confInter2.append(max((p - lowerCI) * 100, 0))
                else:
                    confInter1.append(0)
                    confInter2.append(0)

        # *** Sort fields so they are in descending order of the values in sample 1
        fields = zip(field1, field2, features, confInter1, confInter2)
        fields.sort(reverse=True)
        field1, field2, features, confInter1, confInter2 = zip(*fields)
        features = list(features)

        # *** Truncate feature labels
        selectedFeatures = list(
            self.preferences['Selected exploratory features'])
        if self.preferences['Truncate feature names']:
            length = self.preferences['Length of truncated feature names']

            for i in xrange(0, len(features)):
                if len(features[i]) > length + 3:
                    features[i] = features[i][0:length] + '...'

            for i in xrange(0, len(selectedFeatures)):
                if len(selectedFeatures[i]) > length + 3:
                    selectedFeatures[i] = selectedFeatures[i][0:length] + '...'

        # *** Set figure size
        self.fig.clear()
        figWidth = self.figColWidth * len(features)
        figHeight = self.figHeight
        if figWidth > 256 or figHeight > 256:
            QtGui.QApplication.instance().setOverrideCursor(
                QtGui.QCursor(QtCore.Qt.ArrowCursor))
            self.emptyAxis()
            QtGui.QMessageBox.question(
                self, 'Excessively large plot',
                'The resulting plot is too large to display.')
            QtGui.QApplication.instance().restoreOverrideCursor()
            return

        self.fig.set_size_inches(figWidth, figHeight)
        xLabelBounds, yLabelBounds = self.labelExtents(
            features, 8, 90, [max(max(field1), max(field2))], 8, 0)

        padding = 0.1  # inches
        newFigWidth = figWidth * (1.0 + yLabelBounds.width) + 2 * padding
        self.fig.set_size_inches(
            figWidth * (1.0 + yLabelBounds.width) + 2 * padding, figHeight)

        xOffsetFigSpace = (yLabelBounds.width *
                           figWidth) / newFigWidth + padding / newFigWidth
        yOffsetFigSpace = xLabelBounds.height + padding / figHeight
        axesBar = self.fig.add_axes([
            xOffsetFigSpace, yOffsetFigSpace,
            1.0 - xOffsetFigSpace - padding / newFigWidth,
            1.0 - yOffsetFigSpace - padding / figHeight
        ])

        # *** Plot data
        colWidth = self.figColWidth
        barWidth = (colWidth * 0.9) / 2

        if self.bShowCIs == True:
            rects1 = axesBar.bar(np.arange(len(features)) * colWidth,
                                 field1,
                                 width=barWidth,
                                 color=profile1Colour,
                                 yerr=confInter1,
                                 ecolor='black',
                                 capsize=self.endCapSize)
            rects2 = axesBar.bar(np.arange(len(features)) * colWidth +
                                 barWidth,
                                 field2,
                                 width=barWidth,
                                 color=profile2Colour,
                                 yerr=confInter2,
                                 ecolor='black',
                                 capsize=self.endCapSize)
        else:
            rects1 = axesBar.bar(np.arange(len(features)) * colWidth,
                                 field1,
                                 width=barWidth,
                                 color=profile1Colour)
            rects2 = axesBar.bar(np.arange(len(features)) * colWidth +
                                 barWidth,
                                 field2,
                                 width=barWidth,
                                 color=profile2Colour)

        axesBar.set_xticks(np.arange(len(features)) * colWidth + barWidth)
        axesBar.set_xlim(
            [0, (len(features) - 1.0) * colWidth + 2 * barWidth + 0.1])
        axesBar.set_xticklabels(features, size=8)

        # *** Prettify plot
        legend = axesBar.legend([rects1[0], rects2[0]],
                                (self.sampleName1, self.sampleName2),
                                loc=self.legendPos)
        legend.get_frame().set_linewidth(0)

        for label in legend.get_texts():
            label.set_size(8)

        for label in axesBar.get_xticklabels():
            label.set_size(8)
            label.set_rotation(90)
            if label.get_text() in selectedFeatures:
                label.set_color('red')

        for label in axesBar.get_yticklabels():
            label.set_size(8)

        for a in axesBar.yaxis.majorTicks:
            a.tick1On = False
            a.tick2On = False

        for a in axesBar.xaxis.majorTicks:
            a.tick1On = False
            a.tick2On = False

        for loc, spine in axesBar.spines.iteritems():
            if loc in ['right', 'top']:
                spine.set_color('none')

        self.updateGeometry()
        self.draw()
Beispiel #3
0
    def plot(self, profile, statsResults):
        if len(profile.profileDict) <= 0:
            self.emptyAxis()
            return

        # *** Colour of plot elements
        axesColour = str(self.preferences['Axes colour'].name())
        profile1Colour = str(self.preferences['Sample 1 colour'].name())
        profile2Colour = str(self.preferences['Sample 2 colour'].name())

        # *** Determine most abundant features
        features = []
        field1 = []
        field2 = []
        parentField1 = []
        parentField2 = []

        tables = profile.getLabeledTables()
        for table in tables:
            feature, seq1, seq2, parentSeq1, parentSeq2 = table
            field1.append(seq1)
            field2.append(seq2)
            parentField1.append(parentSeq1)
            parentField2.append(parentSeq2)
            features.append(feature)

        fields = zip(field1, field2, parentField1, parentField2, features)
        fields.sort(reverse=True)
        field1, field2, parentField1, parentField2, features = zip(*fields)

        if len(field1) > self.numFeaturesToShow:
            field1 = list(field1[0:self.numFeaturesToShow])
            field2 = list(field2[0:self.numFeaturesToShow])
            parentField1 = parentField1[0:self.numFeaturesToShow]
            parentField2 = parentField2[0:self.numFeaturesToShow]
            features = list(features[0:self.numFeaturesToShow])
        else:
            field1 = list(field1)
            field2 = list(field2)
            features = list(features)

        # *** Create lists for each quantity of interest and calculate CIs
        wilsonCI = WilsonCI()
        confInter1 = []
        confInter2 = []

        if self.fieldToPlot == 'Number of sequences':
            for i in xrange(0, len(field1)):
                if self.bShowCIs:
                    lowerCI, upperCI, p = wilsonCI.run(field1[i],
                                                       parentField1[i], 0.95,
                                                       1.96)
                    confInter1.append(max((p - lowerCI) * parentField1[i], 0))

                    lowerCI, upperCI, p = wilsonCI.run(field2[i],
                                                       parentField2[i], 0.95,
                                                       1.96)
                    confInter2.append(max((p - lowerCI) * parentField2[i], 0))
                else:
                    confInter1.append(0)
                    confInter2.append(0)

        elif self.fieldToPlot == 'Proportion of sequences (%)':
            for i in xrange(0, len(field1)):
                if self.bShowCIs:
                    lowerCI, upperCI, p = wilsonCI.run(field1[i],
                                                       parentField1[i], 0.95,
                                                       1.96)
                    confInter1.append(max((p - lowerCI) * 100, 0))

                    lowerCI, upperCI, p = wilsonCI.run(field2[i],
                                                       parentField2[i], 0.95,
                                                       1.96)
                    confInter2.append(max((p - lowerCI) * 100, 0))
                else:
                    confInter1.append(0)
                    confInter2.append(0)

                field1[i] = float(field1[i]) * 100 / max(parentField1[i], 1)
                field2[i] = float(field2[i]) * 100 / max(parentField2[i], 1)

        # *** Truncate feature labels
        highlightedFeatures = list(
            self.preferences['Highlighted sample features'])

        truncatedNames = list(features)
        if self.preferences['Truncate feature names']:
            length = self.preferences['Length of truncated feature names']

            for i in xrange(0, len(truncatedNames)):
                if len(truncatedNames[i]) > length + 3:
                    truncatedNames[i] = truncatedNames[i][0:length] + '...'

            for i in xrange(0, len(highlightedFeatures)):
                if len(highlightedFeatures[i]) > length + 3:
                    highlightedFeatures[
                        i] = highlightedFeatures[i][0:length] + '...'

        # *** Find longest label
        longestLabelLen = 0
        for i in xrange(0, len(truncatedNames)):
            if len(truncatedNames[i]) > longestLabelLen:
                longestLabelLen = len(truncatedNames[i])
                longestLabel = truncatedNames[i]

        # *** Set figure size
        self.fig.clear()
        figWidth = self.figColWidth * len(features)
        figHeight = self.figHeight
        if figWidth > 256 or figHeight > 256:
            QtGui.QApplication.instance().setOverrideCursor(
                QtGui.QCursor(QtCore.Qt.ArrowCursor))
            self.emptyAxis()
            QtGui.QMessageBox.question(
                self, 'Excessively large plot',
                'The resulting plot is too large to display.')
            QtGui.QApplication.instance().restoreOverrideCursor()
            return

        self.fig.set_size_inches(figWidth, figHeight)
        xLabelBounds, yLabelBounds = self.labelExtents(
            [longestLabel], 8, 90, ['%.0f' % max(max(field1), max(field2))], 8,
            0)
        yLabelOffset = 0.3
        padding = 0.15  # inches

        newFigWidth = figWidth + yLabelBounds.width / figWidth + 2 * padding + yLabelOffset
        self.fig.set_size_inches(newFigWidth, figHeight)

        xOffsetFigSpace = yLabelBounds.width + padding / newFigWidth + yLabelOffset / newFigWidth
        yOffsetFigSpace = xLabelBounds.height + padding / figHeight
        axesBar = self.fig.add_axes([
            xOffsetFigSpace, yOffsetFigSpace,
            1.0 - xOffsetFigSpace - padding / newFigWidth,
            1.0 - yOffsetFigSpace - padding / figHeight
        ])

        # *** Plot data
        colWidth = self.figColWidth
        barWidth = (colWidth * (self.barWidth / 100.0)) / 2

        if self.bShowCIs == True:
            rects1 = axesBar.bar(np.arange(len(features)) * colWidth,
                                 field1,
                                 width=barWidth,
                                 color=profile1Colour,
                                 yerr=confInter1,
                                 ecolor='black',
                                 capsize=self.endCapSize)
            rects2 = axesBar.bar(np.arange(len(features)) * colWidth +
                                 barWidth,
                                 field2,
                                 width=barWidth,
                                 color=profile2Colour,
                                 yerr=confInter2,
                                 ecolor='black',
                                 capsize=self.endCapSize)
        else:
            rects1 = axesBar.bar(np.arange(len(features)) * colWidth,
                                 field1,
                                 width=barWidth,
                                 color=profile1Colour)
            rects2 = axesBar.bar(np.arange(len(features)) * colWidth +
                                 barWidth,
                                 field2,
                                 width=barWidth,
                                 color=profile2Colour)

        axesBar.set_xticks(np.arange(len(features)) * colWidth + barWidth)
        axesBar.set_xlim(
            [0, (len(features) - 1.0) * colWidth + 2 * barWidth + 0.1])
        axesBar.set_ylim(0, axesBar.get_ylim()[1])
        axesBar.set_xticklabels(truncatedNames, size=8)
        axesBar.set_ylabel(self.fieldToPlot, fontsize=8)

        # *** Mark significant features
        if self.bShowPvalue and statsResults.profile != None:
            offset = axesBar.get_ylim()[1] * 0.02

            x = []
            y = []
            for i in xrange(0, len(features)):
                pValue = float(
                    statsResults.getFeatureStatistic(features[i],
                                                     'pValuesCorrected'))
                if pValue <= self.pValueThreshold:
                    x.append(i * colWidth + barWidth)
                    y.append(max(field1[i], field2[i]) + offset)

            axesBar.plot(x,
                         y,
                         color='k',
                         linestyle='',
                         marker='*',
                         markeredgecolor='k',
                         ms=3)

        # *** Prettify plot
        if self.legendPos != -1:
            legend = axesBar.legend(
                [rects1[0], rects2[0]],
                (profile.sampleNames[0], profile.sampleNames[1]),
                loc=self.legendPos)
            legend.get_frame().set_linewidth(0)

        for label in axesBar.get_xticklabels():
            label.set_rotation(90)
            if label.get_text() in highlightedFeatures:
                label.set_color('red')

        for a in axesBar.yaxis.majorTicks:
            a.tick1On = False
            a.tick2On = False

        for a in axesBar.xaxis.majorTicks:
            a.tick1On = False
            a.tick2On = False

        for loc, spine in axesBar.spines.iteritems():
            if loc in ['right', 'top']:
                spine.set_color('none')
            else:
                spine.set_color(axesColour)

        self.updateGeometry()
        self.draw()
Beispiel #4
0
    def plot(self, profile, statsResults):
        if len(profile.profileDict) <= 0:
            self.emptyAxis()
            return

        if len(profile.profileDict) > 10000:
            QtGui.QApplication.instance().setOverrideCursor(
                QtGui.QCursor(QtCore.Qt.ArrowCursor))
            reply = QtGui.QMessageBox.question(
                self, 'Continue?', 'Profile contains ' +
                str(len(profile.profileDict)) + ' features. ' +
                'It may take several seconds to generate this plot. Exploring the data at a higher hierarchy level is recommended. '
                + 'Do you wish to continue?', QtGui.QMessageBox.Yes,
                QtGui.QMessageBox.No)
            QtGui.QApplication.instance().restoreOverrideCursor()
            if reply == QtGui.QMessageBox.No:
                self.emptyAxis()
                return

        # *** Colour of plot elements
        axesColour = str(self.preferences['Axes colour'].name())
        profile1Colour = str(self.preferences['Sample 1 colour'].name())
        profile2Colour = str(self.preferences['Sample 2 colour'].name())

        # *** Create lists for each quantity of interest and calculate CIs
        tables = profile.getLabeledTables()
        features = []
        field1 = []
        field2 = []

        wilsonCI = WilsonCI()
        confInter1 = []
        confInter2 = []
        for table in tables:
            feature, seq1, seq2, parentSeq1, parentSeq2 = table

            features.append(feature)
            field1.append(float(seq1) * 100 / max(parentSeq1, 1))
            field2.append(float(seq2) * 100 / max(parentSeq2, 1))

            if self.bShowCIs:
                lowerCI, upperCI, p = wilsonCI.run(seq1, parentSeq1, 0.95,
                                                   1.96)
                confInter1.append(
                    [max(lowerCI * 100, 0),
                     min(upperCI * 100, 100)])

                lowerCI, upperCI, p = wilsonCI.run(seq2, parentSeq2, 0.95,
                                                   1.96)
                confInter2.append(
                    [max(lowerCI * 100, 0),
                     min(upperCI * 100, 100)])

        # *** Set figure size
        self.fig.clear()
        self.fig.set_size_inches(self.figWidth, self.figHeight)

        if self.bShowHistograms:
            histogramSizeX = self.histogramSize / self.figWidth
            histogramSizeY = self.histogramSize / self.figHeight
        else:
            histogramSizeX = 0.0
            histogramSizeY = 0.0

        padding = 0.1  # inches
        xOffsetFigSpace = (0.4 + padding) / self.figWidth
        yOffsetFigSpace = (0.3 + padding) / self.figHeight
        axesScatter = self.fig.add_axes([
            xOffsetFigSpace, yOffsetFigSpace, 1.0 - xOffsetFigSpace -
            histogramSizeX - (2 * padding) / self.figWidth, 1.0 -
            yOffsetFigSpace - histogramSizeY - (2 * padding) / self.figHeight
        ])

        if self.bShowHistograms:
            axesTopHistogram = self.fig.add_axes([
                xOffsetFigSpace,
                1.0 - histogramSizeY - padding / self.figHeight,
                1.0 - xOffsetFigSpace - histogramSizeX -
                (2 * padding) / self.figWidth, histogramSizeY
            ])

            axesRightHistogram = self.fig.add_axes([
                1.0 - histogramSizeX - padding / self.figWidth,
                yOffsetFigSpace, histogramSizeX, 1.0 - yOffsetFigSpace -
                histogramSizeY - (2 * padding) / self.figHeight
            ])

        # *** Handle mouse events
        tooltips = []
        for i in xrange(0, len(field1)):
            tooltip = features[i] + '\n\n'
            tooltip += 'Sequences in ' + profile.sampleNames[0] + ': ' + str(
                tables[i][1]) + '\n'
            tooltip += 'Sequences in ' + profile.sampleNames[1] + ': ' + str(
                tables[i][2]) + '\n\n'
            tooltip += (profile.sampleNames[0] +
                        ' percentage: %.3f' % field1[i]) + '\n'
            tooltip += (profile.sampleNames[1] +
                        ' percentage: %.3f' % field2[i]) + '\n\n'
            tooltip += 'Difference between proportions (%): ' + (
                '%.3f' % (field1[i] - field2[i])) + '\n'

            if field2[i] != 0:
                tooltip += 'Ratio of proportions: %.3f' % (field1[i] /
                                                           field2[i])
            else:
                tooltip += 'Ratio of proportions: undefined'

            if statsResults.profile != None:
                pValue = statsResults.getFeatureStatisticAsStr(
                    features[i], 'pValues')
                pValueCorrected = statsResults.getFeatureStatisticAsStr(
                    features[i], 'pValuesCorrected')
                tooltip += '\n\n'
                tooltip += 'p-value: ' + pValue + '\n'
                tooltip += 'Corrected p-value: ' + pValueCorrected

            tooltips.append(tooltip)

        self.plotEventHandler = PlotEventHandler(field1, field2, tooltips)

        self.mouseEventCallback(self.plotEventHandler)

        # *** Calculate R^2 value
        slope, intercept, r_value, p_value, std_err = linregress(
            field1, field2)

        # *** Plot data

        # set visual properties of all points
        colours = []
        highlightedField1 = []
        highlightedField2 = []
        highlighColours = []
        for i in xrange(0, len(field1)):
            if field1[i] > field2[i]:
                colours.append(profile1Colour)
            else:
                colours.append(profile2Colour)

            if features[i] in self.preferences['Highlighted sample features']:
                highlightedField1.append(field1[i])
                highlightedField2.append(field2[i])
                highlighColours.append(colours[i])

        # scatter plot
        axesScatter.scatter(field1,
                            field2,
                            c=colours,
                            s=self.markerSize,
                            zorder=5)
        if len(highlightedField1) > 0:
            axesScatter.scatter(highlightedField1,
                                highlightedField2,
                                c=highlighColours,
                                s=self.markerSize,
                                edgecolors='red',
                                linewidth=2,
                                zorder=10)

        # plot CIs
        if self.bShowCIs:
            xlist = []
            ylist = []
            for i in xrange(0, len(field1)):
                # horizontal CIs
                xlist.append(confInter1[i][0])
                xlist.append(confInter1[i][1])
                xlist.append(None)
                ylist.append(field2[i])
                ylist.append(field2[i])
                ylist.append(None)

                # vertical CIs
                xlist.append(field1[i])
                xlist.append(field1[i])
                xlist.append(None)
                ylist.append(confInter2[i][0])
                ylist.append(confInter2[i][1])
                ylist.append(None)

            axesScatter.plot(xlist,
                             ylist,
                             '-',
                             color='gray',
                             antialiased=False)

        # plot y=x line
        maxProportion = max(max(field1), max(field2)) * 1.05
        axesScatter.plot([0, maxProportion], [0, maxProportion],
                         color=axesColour,
                         linestyle='dashed',
                         marker='',
                         zorder=1)

        axesScatter.set_xlabel(profile.sampleNames[0] + ' (%)')
        axesScatter.set_ylabel(profile.sampleNames[1] + ' (%)')

        if self.bShowR2:
            axesScatter.text(0.02,
                             0.98,
                             r'R$^2$ = ' + ('%0.3f' % r_value**2),
                             horizontalalignment='left',
                             verticalalignment='top',
                             transform=axesScatter.transAxes)

        axesScatter.set_xlim(0, maxProportion)
        axesScatter.set_ylim(0, maxProportion)

        # *** Prettify scatter plot
        for line in axesScatter.yaxis.get_ticklines():
            line.set_color(axesColour)

        for line in axesScatter.xaxis.get_ticklines():
            line.set_color(axesColour)

        for loc, spine in axesScatter.spines.iteritems():
            spine.set_color(axesColour)

        # plot histograms
        if not self.bShowHistograms:
            for a in axesScatter.yaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for a in axesScatter.xaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for line in axesScatter.yaxis.get_ticklines():
                line.set_color(axesColour)

            for line in axesScatter.xaxis.get_ticklines():
                line.set_color(axesColour)

            for loc, spine in axesScatter.spines.iteritems():
                if loc in ['right', 'top']:
                    spine.set_color('none')
                else:
                    spine.set_color(axesColour)

        else:  # show histograms
            # plot top histogram
            axesTopHistogram.xaxis.set_major_formatter(NullFormatter())
            pdf, bins, patches = axesTopHistogram.hist(
                field1, bins=self.numBins, facecolor=profile1Colour)
            axesTopHistogram.set_xlim(axesScatter.get_xlim())
            axesTopHistogram.set_yticks([0, max(pdf)])
            axesTopHistogram.set_ylim([0, max(pdf) * 1.05])

            # plot right histogram
            axesRightHistogram.yaxis.set_major_formatter(NullFormatter())
            pdf, bins, patches = axesRightHistogram.hist(
                field2,
                bins=self.numBins,
                orientation='horizontal',
                facecolor=profile2Colour)
            axesRightHistogram.set_ylim(axesScatter.get_ylim())
            axesRightHistogram.set_xticks([0, max(pdf)])
            axesRightHistogram.set_xlim([0, max(pdf) * 1.05])

            # *** Prettify histogram plot
            for a in axesTopHistogram.yaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for a in axesTopHistogram.xaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for line in axesTopHistogram.yaxis.get_ticklines():
                line.set_color(axesColour)

            for line in axesTopHistogram.xaxis.get_ticklines():
                line.set_color(axesColour)

            for loc, spine in axesTopHistogram.spines.iteritems():
                if loc in ['right', 'top']:
                    spine.set_color('none')
                else:
                    spine.set_color(axesColour)

            for a in axesRightHistogram.yaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for a in axesRightHistogram.xaxis.majorTicks:
                a.tick1On = True
                a.tick2On = False

            for line in axesRightHistogram.yaxis.get_ticklines():
                line.set_color(axesColour)

            for line in axesRightHistogram.xaxis.get_ticklines():
                line.set_color(axesColour)

            for loc, spine in axesRightHistogram.spines.iteritems():
                if loc in ['right', 'top']:
                    spine.set_color('none')
                else:
                    spine.set_color(axesColour)

        self.updateGeometry()
        self.draw()