def _visualizeHistogram(self, e=None):
        views = []
        numberOfBins = self.visualizeHistogram.get()
        goodScores = []
        badScores = []
        if hasattr(self.protocol, "outputParticles"):
            goodScores += [
                part._xmipp_scoreEmptiness.get()
                for part in self.protocol.outputParticles
            ]

        if hasattr(self.protocol, "eliminatedParticles"):
            badScores += [
                part._xmipp_scoreEmptiness.get()
                for part in self.protocol.eliminatedParticles
            ]

        plotter = EmPlotter()
        plotter.createSubPlot("Emptiness Score", "Emptiness Score (a.u.)",
                              "# of Particles")

        values = [goodScores, badScores]
        labels = ["Passed particles", "Discarded particles"]
        colors = ['green', 'red']

        plotMultiHistogram(values, colors, labels, numberOfBins, plotter,
                           views)

        return views
Ejemplo n.º 2
0
    def _visualizeHistogram(self, e=None):
        views = []
        numberOfBins = self.visualizeHistogram.get()
        if hasattr(self.protocol, "outputCTF"):
            numberOfBins = min(numberOfBins, self.protocol.outputCTF.getSize())
            plotter = EmPlotter()
            plotter.createSubPlot("Resolution Discrepancies histogram",
                                  "Resolution (A)", "# of Comparisons")
            resolution = [
                ctf.getResolution() for ctf in self.protocol.outputCTF
            ]
            plotter.plotHist(resolution, nbins=numberOfBins)
            views.append(plotter)

        if hasattr(self.protocol, "outputCTFDiscarded"):
            numberOfBins = min(numberOfBins,
                               self.protocol.outputCTFDiscarded.getSize())
            plotter = EmPlotter()
            plotter.createSubPlot(
                "Resolution Discrepancies histogram (discarded)",
                "Resolution (A)", "# of Comparisons")
            resolution = [
                ctf.getResolution() for ctf in self.protocol.outputCTFDiscarded
            ]
            plotter.plotHist(resolution, nbins=numberOfBins)
            views.append(plotter)
        return views
Ejemplo n.º 3
0
    def _plotHistogram(self, param=None):
        md = MetaData()
        md.read(self.protocol._getFileName(FN_METADATA_HISTOGRAM))
        x_axis = []
        y_axis = []

        i = 0
        for idx in md:
            x_axis_ = md.getValue(MDL_X, idx)
            if i == 0:
                x0 = x_axis_
            elif i == 1:
                x1 = x_axis_
            y_axis_ = md.getValue(MDL_COUNT, idx)

            i += 1
            x_axis.append(x_axis_)
            y_axis.append(y_axis_)

        plotter = EmPlotter()
        plotter.createSubPlot("Resolutions Histogram", "Resolution (A)",
                              "# of Counts")

        barwidth = x1 - x0

        plotter.plotDataBar(x_axis, y_axis, barwidth)

        return [plotter]
Ejemplo n.º 4
0
 def _plotHistogram(self, param=None):
     imageFile = self.protocol._getFileName(FN_RESOLMAP)
     img = ImageHandler().read(imageFile)
     imgData = img.getData()
     imgList = imgData.flatten()
     imgListNoZero = filter(lambda x: x > 0, imgList)
     nbins = 30
     plotter = EmPlotter(x=1, y=1, mainTitle="  ")
     plotter.createSubPlot("Resolution histogram",
                           "Resolution (A)", "# of Counts")
     plotter.plotHist(list(imgListNoZero), nbins)
     return [plotter]
Ejemplo n.º 5
0
    def _showHistogram(self, param=None):
        fn = self.protocol._getFileName('output_hist')
        with open(fn) as f:
            views = []
            numberOfBins = 10
            plotter = EmPlotter()
            plotter.createSubPlot("PSF Resolution histogram", "Resolution (A)",
                                  "Ang (str)")
            resolution = [float(line.strip()) for line in f]
        plotter.plotHist(resolution, nbins=numberOfBins)
        plotter.show()

        return views.append(plotter)
Ejemplo n.º 6
0
 def _plotHistogram(self, param=None):
     imageFile = self.protocol._getFileName(RESMAP_VOL)
     img = ImageHandler().read(imageFile)
     imgData = img.getData()
     imgList = imgData.flatten()
     imgDataMax = self.getBackGroundValue(imgList)
     imgListNoZero = filter(lambda x: 0 < x < imgDataMax, imgList)
     nbins = 30
     plotter = EmPlotter(x=1, y=1, mainTitle="  ")
     plotter.createSubPlot("Resolution histogram", "Resolution (A)",
                           "# of Counts")
     plotter.plotHist(imgListNoZero, nbins)
     return [plotter]
def plotMultiHistogram(valuesList,
                       colors=None,
                       legend=None,
                       numOfBins=100,
                       plotter=None,
                       views=None,
                       includeEmpties=False):
    """ Values list must be a n-list of list,
        where n is the number of the subhistograms to plot.
        Multiple histograms will be plot in the same chart
        If no views is passed, a new list-views will be returned with the hist.
        If no plotter is passed, a new generic one will be created.
    """

    if not all([isinstance(x, list) for x in valuesList]):
        print("Not all items in values list are lists. Returning...")
        return

    if colors is None:
        from matplotlib import colors
        from random import shuffle
        colors = colors.cnames.keys()
        shuffle(colors)

    if any([len(x) for x in valuesList]):
        if plotter is None:
            plotter = EmPlotter()
            plotter.createSubPlot("Histogram", "Score", "# of Items")

        w1 = None
        finalLegend = []
        for idx, values in enumerate(valuesList):
            if values or includeEmpties:
                if w1 is None:
                    w1 = (max(values) - min(values)) / numOfBins
                else:
                    numOfBins = int((max(values) - min(values)) / w1)

                plotter.plotHist(values, nbins=numOfBins, color=colors[idx])
                if legend:
                    finalLegend.append(legend[idx])

        if finalLegend:
            plotter.legend(labels=finalLegend)

        if views is None:
            views = [plotter]
        else:
            views.append(plotter)

        return views
Ejemplo n.º 8
0
    def _plotFactorMaps(self, param=None):
        # Parse the file
        fn = self.protocol._getFileName('imcFile')
        f = open(fn)
        values = f.readline().split()
        n = int(values[0])  # Number of images
        nf = int(values[1])  # Number of factors

        x = self.firstFactor.get()
        y = self.secondFactor.get()
        xFactors = []
        yFactors = []
        i = 0
        while i < n:
            imgFactors = []
            while len(imgFactors) < nf:
                values = f.readline().split()
                imgFactors += [float(v) for v in values]
            xFactors.append(imgFactors[x - 1])
            yFactors.append(imgFactors[y - 1])
            i += 1
        f.close()

        # Create the plot
        xplotter = EmPlotter(1, 1)
        a = xplotter.createSubPlot("Factor %d vs %d" % (x, y), "Factor %d" % x,
                                   "Factor %d" % y)
        a.plot(xFactors, yFactors, 'o')

        return [xplotter]
Ejemplo n.º 9
0
    def plot1D(self, ctfSet, ctfId):
        ctfModel = ctfSet[ctfId]
        psdFn = ctfModel.getPsdFile()
        fn = os.path.join(
            pwutils.removeExt(psdFn).replace("_ctf", "") + '_EPA.log')

        xplotter = EmPlotter(windowTitle='GCTF results')
        plot_title = '%s # %d\n' % (ctfSet.getTsId(),
                                    ctfId) + getPlotSubtitle(ctfModel)
        a = xplotter.createSubPlot(plot_title, 'Resolution (Angstroms)', 'CTF')
        a.invert_xaxis()
        version = Plugin.getActiveVersion()
        curves = [1, 4, 5] if version == '1.18' else [1, 3, 4]

        for i in curves:
            _plotCurve(a, i, fn)
        xplotter.showLegend([
            'simulated CTF',
            # 'equiphase avg.',
            # 'bg', #  only for v1.18
            'equiphase avg. - bg',
            'cross correlation'
        ])
        a.grid(True)

        return xplotter
Ejemplo n.º 10
0
    def _plotHistogram(self, param=None):
        """ First we parse the MSA plt:
        first column: cumulative percent.
        second column: iteration number.
        """

        iters = []
        cumPercents = []
        fn = self.protocol.getOutputPlt()
        with open(fn) as f:
            lines_after_2 = f.readlines()[2:]
            for line in lines_after_2:
                values = line.split()
                cumPercents.append(float(values[0]))
                iters.append(int(float(values[1])))
        f.close()

        width = 0.85
        xplotter = EmPlotter()
        a = xplotter.createSubPlot(
            'Behaviour of sum of eigenvalues during analysis',
            'Iteration number', '%')
        a.bar(iters, cumPercents, width, color='b')

        return [xplotter]
Ejemplo n.º 11
0
    def _showMollweide(self, param=None):
        """ This plot script is based on two scripts by their respective authors:
            - PlotOD.py from cryoEF package
            - https://github.com/PirateFernandez/python3_rln_scripts/blob/main/rln_star_2_mollweide_any_star.py
        """
        import numpy as np
        from matplotlib import spines
        from scipy.stats import gaussian_kde

        views = []
        xplotter = EmPlotter(
            windowTitle="Mollweide projection plot of orientation distribution"
        )
        fn = np.genfromtxt(self.protocol._getFileName('anglesFn'),
                           delimiter=' ')
        phi = fn[:, 0]
        theta = fn[:, 1]

        # Convert degrees to radians and obey angular range conventions
        x = phi / 180 * np.pi  # x is the phi angle (longitude)
        y = theta / 180 * np.pi  # y is the theta angle (latitude)
        y = -1 * y + np.pi / 2  # The convention in RELION is [0, 180] for theta,
        # whereas for the projection function it is [90, -90], so this conversion is required.
        vertical_rad = np.vstack([y, x])
        m = gaussian_kde(vertical_rad)(vertical_rad)

        ax = xplotter.createSubPlot('', 'phi', 'theta', projection="mollweide")
        # Plot your points on the projection
        #ax.plot(x, y, ',', alpha=0.5, color='#64B5F6')  # alpha - transparency (from 0 to 1), color - specify hex code
        a = ax.scatter(x, y, cmap='plasma', c=m, s=2, alpha=0.4)
        # Draw the horizontal and the vertical grid lines. Can add more grid lines if required.
        major_ticks_x = [-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi]
        major_ticks_y = [-np.pi / 2, -np.pi / 4, 0, np.pi / 4, np.pi / 2]
        ax.set_xticks(major_ticks_x)
        ax.set_yticks(major_ticks_y)
        ax.set_xticklabels([
            '-180$^\circ$', '-90$^\circ$', '0$^\circ$', '90$^\circ$',
            '180$^\circ$'
        ],
                           color='grey')
        ax.set_yticklabels([
            '-90$^\circ$', '-45$^\circ$', '0$^\circ$', '45$^\circ$',
            '90$^\circ$'
        ],
                           color='grey')

        # Set the color and the thickness of the grid lines
        ax.grid(which='both', linestyle='--', linewidth=1, color='#555F61')

        # Set the color and the thickness of the outlines
        for child in ax.get_children():
            if isinstance(child, spines.Spine):
                child.set_color('#555F61')

        xplotter.getColorBar(a)
        xplotter.tightLayout()
        xplotter.show()

        return views.append(xplotter)
Ejemplo n.º 12
0
    def _plotHistogram(self, param=None):
        md = MetaData()
        md.read(self.protocol._getExtraPath(FN_METADATA_HISTOGRAM))
        x_axis = []
        y_axis = []

        for idx in md:
            x_axis_ = md.getValue(MDL_X, idx)
            y_axis_ = md.getValue(MDL_COUNT, idx)

            x_axis.append(x_axis_)
            y_axis.append(y_axis_)

        _plotter = EmPlotter()
        _plotter.createSubPlot("Resolutions Histogram",
                               "Resolution (A)", "# of Counts")
        barwidth = (x_axis[-1] - x_axis[0]) / len(x_axis)

        _plotter.plotDataBar(x_axis[:-2], y_axis[:-2], barwidth)

        return [_plotter]
Ejemplo n.º 13
0
    def getCTFViews(self, ctfSet):
        # This could be used by any CTF viewer to show CTF plus, phaseShift plot
        # if applies.
        # Return phaseShift plot if apply
        firstCtf = ctfSet.getFirstItem()

        if firstCtf.hasPhaseShift():
            phase_shift = []

            for ctf in ctfSet.iterItems():
                phShift = ctf.getPhaseShift()
                phase_shift.append(phShift)

            plotter = EmPlotter()
            plotter.createSubPlot("Phase Shift estimation", "Number of CTFs",
                                  "Phase Shift")
            plotter.plotData(np.arange(0, len(phase_shift)), phase_shift)
            self._views.append(plotter)

        # Return Standard CTF view (showJ)
        self._views.append(CtfView(self._project, ctfSet))
Ejemplo n.º 14
0
    def _plotDendrogram(self, e=None):
        xplotter = EmPlotter()
        self.plt = xplotter.createSubPlot("Dendrogram", "", "")
        self.step = 0.25
        self.rightMost = 0.0  # Used to arrange leaf nodes at the bottom

        node = self.protocol.buildDendrogram()
        self.plotNode(node, self.minHeight.get())
        self.plt.set_xlim(0., self.rightMost + self.step)
        self.plt.set_ylim(-10, 105)

        return [xplotter]
Ejemplo n.º 15
0
    def _visualizeHistogram(self, e=None):
        views = []
        numberOfBins = self.visualizeHistogram.get()

        outCoords = self.protocol.getOutput()
        if outCoords:
            mdLabel = emlib.MDL_GOOD_REGION_SCORE
            if getXmippAttribute(outCoords.getFirstItem(), mdLabel):
                plotter = EmPlotter()
                plotter.createSubPlot("Deep micrograph score",
                                      "Deep micrograph score",
                                      "Number of Coordinates")
                cScores = [getXmippAttribute(coord, mdLabel).get()
                           for coord in outCoords]
                plotter.plotHist(cScores, nbins=numberOfBins)
                views.append(plotter)
            else:
                print(" > 'outputCoordinates' don't have 'xmipp_zScoreDeepLearning2' label.")
        else:
            print(" > Output not ready yet.")

        return views
Ejemplo n.º 16
0
    def visualize(self, obj, **kwargs):
        self.prot = obj

        # Experimental
        x = np.asarray([float(xi.strip()) for xi in self.prot.x.get().split(',')])
        p = np.asarray([float(xi.strip()) for xi in self.prot.p.get().split(',')])
        if self.prot.descending:
            x=np.flip(x,0)
            p=np.flip(p,0)
        logx = np.log(x)
        logx = np.insert(logx, 0, np.log(np.min(x)/2))
        p=p/np.sum(p)

        barx = []
        bary = p
        widths = []
        locx = []
        labels = []

        for i in range (0,p.shape[0]):
            barx.append(0.5*(logx[i]+logx[i+1]))
            widths.append(logx[i+1]-logx[i])
            locx.append(np.log(x[i]))
            labels.append("log(%4.2f)"%x[i])

        plotter =EmPlotter(style='seaborn-whitegrid')
        ax = plotter.createSubPlot("Particle size distribution", "log(Particle size)", "Fraction")
        ax.bar(barx, bary, width=widths, linewidth=1, label="Experimental", edgecolor="black")
        plt.xticks(locx, labels)

        # Theoretical
        fhSummary = open(self.prot._getPath("summary.txt"))
        lineno=0
        for line in fhSummary.readlines():
            if lineno==0:
                mu = float((line.split()[2]).split('=')[1])
            elif lineno==1:
                sigma = float((line.split()[2]).split('=')[1])
            lineno+=1
        fhSummary.close()

        logx = np.arange(np.min(logx),np.max(logx),(np.max(logx)-np.min(logx))/100)
        theox = norm.pdf(logx,mu,sigma)
        ax.plot(logx,theox/np.max(theox)*np.max(bary), color='red', label='Theoretical (log-normal)')

        # General
        ax.legend()
        ax.grid(True)
        plotter.show()
Ejemplo n.º 17
0
def createCtfPlot(ctfSet, ctfId):
    """ Create EmPlotter instance. """
    ctfModel = ctfSet[ctfId]
    psdFn = ctfModel.getPsdFile()
    fn = removeExt(psdFn) + "_avrot.txt"
    xplotter = EmPlotter(windowTitle='CTFFind results')
    plot_title = getPlotSubtitle(ctfModel)
    a = xplotter.createSubPlot(plot_title, 'Spacial frequency (1/A)',
                               'Amplitude (or cross-correlation)')
    legendName = ['Amplitude spectrum', 'CTF Fit', 'Quality of fit']
    _plotCurves(a, fn)
    xplotter.showLegend(legendName, loc='upper right')
    a.set_ylim([-0.1, 1.1])
    a.grid(True)
    xplotter.show()
Ejemplo n.º 18
0
    def show(self, form, *args):
        prot = form.protocol
        defocusGroups = prot.createDefocusGroups()
        print(defocusGroups)

        plotter = EmPlotter(windowTitle='%d Defocus Groups' %
                            len(defocusGroups),
                            figsize=(8, 6))
        ax = plotter.createSubPlot("", "defocus (A)", "count", 1, 1)

        for group in defocusGroups:
            ax.bar(group.minDefocus,
                   group.count,
                   group.maxDefocus - group.minDefocus,
                   align='edge')

        plotter.show()
Ejemplo n.º 19
0
    def _showGuinier(self, volume):
        nrefs = len(self._refsList)
        gridsize = self._getGridSize(nrefs)
        guinierFn = volume + ".guinier"

        d2 = self._getGuinierValue(guinierFn, 0)

        legends = ["lnFweighted ln(F)", "corrected ln(F)", "model"]
        xplotter = EmPlotter(*gridsize, windowTitle='Guinier Plots')
        subPlot = xplotter.createSubPlot(basename(volume),
                                         'd^-2(A^-2)',
                                         'ln(F)',
                                         yformat=False)
        for i, legend in enumerate(legends):
            y = self._getGuinierValue(guinierFn, i + 2)
            subPlot.plot(d2, y)
            xplotter.showLegend(legends)
        subPlot.grid(True)
        return xplotter
Ejemplo n.º 20
0
    def _createScatterPlot(self, rmax, colorzaxis=False):
        gridsize = self._getGridSize(1)
        xplotter = EmPlotter(x=gridsize[0],
                             y=gridsize[1],
                             windowTitle='Tilt geometry plot')
        plot_title = 'Tilt pair parameter plot'
        a = xplotter.createSubPlot(plot_title,
                                   'Tilt axis',
                                   'Tilt angle',
                                   projection='polar')

        datap, r, theta, zaxis = self._getValues()

        if colorzaxis:
            a.scatter(theta, r, c=zaxis)
        else:
            a.scatter(theta, r)
        a.set_rmax(rmax)

        return xplotter
Ejemplo n.º 21
0
    def _plotHistogram(self, param=None):
        """ First we parse the cas_EIG file and we read:
        first line: take the number of eigen values.
        then one line per factor and we read the percent and cumulative percent.
        """
        from numpy import arange
        from matplotlib.ticker import FormatStrFormatter

        fn = self.protocol._getFileName('eigFile')
        f = open(fn)
        values = f.readline().split()
        n = int(values[0])  # Number of factors
        factors = arange(1, n + 1)
        percents = []
        cumPercents = []

        for i in factors:
            values = f.readline().split()
            percents.append(float(values[1]))
            cumPercents.append(float(values[2]))

        f.close()

        width = 0.85
        xplotter = EmPlotter()
        a = xplotter.createSubPlot('Eigenvalues histogram',
                                   'Eigenvalue number', '%')
        a.set_xticks(factors + 0.45)
        a.xaxis.set_major_formatter(FormatStrFormatter('%1.0f'))
        bars = a.bar(factors, percents, width, color='b')

        for i, rect in enumerate(bars):
            h = rect.get_height()
            a.text(rect.get_x() + rect.get_width() / 2.,
                   h + 0.3,
                   '%d' % cumPercents[i],
                   ha='center',
                   va='bottom')
        a.set_ylim([0, percents[0] + 5])

        return [xplotter]
Ejemplo n.º 22
0
def createCtfPlot(ctfSet, ctfId):
    ctfModel = ctfSet[ctfId]
    psdFn = ctfModel.getPsdFile()
    fn = pwutils.removeExt(psdFn) + "_EPA.log"
    xplotter = EmPlotter(windowTitle='CTF Fitting')
    plot_title = getPlotSubtitle(ctfModel)
    a = xplotter.createSubPlot(plot_title, 'Resolution (Angstroms)', 'CTF')
    a.invert_xaxis()
    version = Plugin.getActiveVersion()
    curves = [1, 4, 5] if version == '1.18' else [1, 3, 4]

    for i in curves:
        _plotCurve(a, i, fn)
    xplotter.showLegend([
        'simulated CTF',
        # 'equiphase avg.',
        # 'bg', #  only for v1.18
        'equiphase avg. - bg',
        'cross correlation'
    ])
    a.grid(True)
    xplotter.show()
Ejemplo n.º 23
0
    def _showVolumeColorSlices(self, param=None):
        imageFile = self.protocol._getFileName(RESMAP_VOL)
        imgData, _, _, _ = self.getImgData(imageFile)

        xplotter = EmPlotter(x=2,
                             y=2,
                             mainTitle="Local Resolution Slices "
                             "along %s-axis." % self._getAxis())
        # The slices to be shown are close to the center. Volume size is divided
        # in segments, the fourth central ones are selected i.e. 3,4,5,6
        for i in list(range(3, 7)):
            sliceNumber = self.getSlice(i, imgData)
            a = xplotter.createSubPlot("Slice %s" % (sliceNumber + 1), '', '')
            matrix = self.getSliceImage(imgData, sliceNumber, self._getAxis())
            plot = xplotter.plotMatrix(a,
                                       matrix,
                                       self.lowest.get(),
                                       self.highest.get(),
                                       cmap=self.getColorMap(),
                                       interpolation="nearest")
        xplotter.getColorBar(plot)
        return [xplotter]
Ejemplo n.º 24
0
 def _showOneColorslice(self, param=None):
     imageFile = self.protocol._getFileName(RESMAP_VOL)
     imgData, _, _, volDims = self.getImgData(imageFile)
     print(volDims)
     xplotter = EmPlotter(x=1,
                          y=1,
                          mainTitle="Local Resolution Slices "
                          "along %s-axis." % self._getAxis())
     sliceNumber = self.sliceNumber.get()
     if sliceNumber < 0:
         sliceNumber = volDims[0] / 2
     else:
         sliceNumber -= 1
     # sliceNumber has no sense to start in zero
     a = xplotter.createSubPlot("Slice %s" % (sliceNumber + 1), '', '')
     matrix = self.getSliceImage(imgData, sliceNumber, self._getAxis())
     plot = xplotter.plotMatrix(a,
                                matrix,
                                self.lowest.get(),
                                self.highest.get(),
                                cmap=self.getColorMap(),
                                interpolation="nearest")
     xplotter.getColorBar(plot)
     return [xplotter]
    def _showFSC(self, paramName=None):
        threshold = self.resolutionThresholdFSC.get()
        iterations = self._getIterations()
        groups = self._getGroups()

        if self.isGoldStdProt():
            template = 'fscdoc_m_%02d.stk'
            title = 'Masked FSC'
        else:
            template = 'fscdoc_%02d.stk'
            title = 'FSC'

        if self.groupFSC == 0:  # group by iterations
            files = [(it, self._getFinalPath(template % it))
                     for it in iterations]
            legendPrefix = 'iter'
        else:
            it = iterations[-1]  # show only last iteration
            legendPrefix = 'group'

            def group(f):  # retrieve the group number
                return int(f.split('_')[-1].split('.')[0])

            groupFiles = glob(self._getFinalPath('ofscdoc_%02d_???.stk' % it))
            groupFiles.sort()
            files = [(group(f), f) for f in groupFiles if group(f) in groups]
            if not files:  # empty files
                return [
                    self.errorMessage("Please select valid groups to display",
                                      title="Wrong groups selection")
                ]

        plotter = EmPlotter(x=1, y=1, windowTitle='Resolution FSC')
        a = plotter.createSubPlot(title, 'Angstroms^-1', 'FSC', yformat=False)
        legends = []
        for it, fscFile in files:
            if os.path.exists(fscFile):
                self._plotFSC(a, fscFile)
                legends.append('%s %d' % (legendPrefix, it))
            else:
                print("Missing file: ", fscFile)

        # plot final FSC curve (from BP)
        if self.groupFSC == 0 and not self.isGoldStdProt():
            lastIter = self.protocol._getLastIterNumber()
            if lastIter in iterations:
                fscFinalFile = self._getFinalPath('ofscdoc_%02d.stk' %
                                                  lastIter)
                if os.path.exists(fscFinalFile):
                    self._plotFSC(a, fscFinalFile)
                    legends.append('final')

        if threshold < self.maxfsc:
            a.plot([self.minInv, self.maxInv], [threshold, threshold],
                   color='black',
                   linestyle='--')

        plotter.showLegend(legends)
        a.grid(True)

        return [plotter]