Exemple #1
0
    def __spacetime_diagram_o_frame(self):
        # from (x',t') to (x,t)
        def tr(x_prime, t_prime):
            x_prime, t_prime = np.asarray(x_prime), np.asarray(t_prime)
            return self.lorentz_transformations.transform(
                x_prime, t_prime, -self.velocity)

        # form (x,t) to (x',t')
        def inv_tr(x, t):
            x, t = np.asarray(x), np.asarray(t)
            return self.lorentz_transformations.transform(x, t, self.velocity)

        grid_helper = GridHelperCurveLinear((tr, inv_tr))
        ax = Subplot(self.fig, 1, 2, 1, grid_helper=grid_helper) if self.showOPrime \
            else Subplot(self.fig, 1, 1, 1, grid_helper=grid_helper)
        self.fig.add_subplot(ax)

        ax.set_xlabel("x", loc="center")
        ax.set_ylabel("t", loc="center")

        # O' x axis
        ax.axis["x1"] = x1 = ax.new_floating_axis(1, 0)
        x1.label.set_text("x'")

        # O' t axis
        ax.axis["t1"] = t1 = ax.new_floating_axis(0, 0)
        t1.label.set_text("t'")

        self.__add_x_and_y_axis(ax)
        ax.format_coord = self.__format_coord_o_frame

        self.__remove_ticks(ax, x1, t1)

        self.world_lines_plotter.plot(plt, ax, self.velocity)
Exemple #2
0
    def setup_content(self):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, axisbg=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.update()
Exemple #3
0
    def setup_content(self, status_callback, marker_callback):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, facecolor=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.mtc = MotionTracker(self, status_callback)
        self.cc = ClickCatcher(self, marker_callback)
Exemple #4
0
def plotISIDistributions(sessions,groups=None,sessionTypes=None,samplingRate=30000.0,save=False,fname=None,figsize=(10,6)):
    """Plots the isi distributions for all the cells in the given sessions"""
    fig = plt.figure(figsize=figsize)
    fig.subplots_adjust(left=0.05,right=.95)
    ISIs = {}
    ncells = 0
    if sessionTypes != None:
        sessionTypes = dict(zip(sessions,sessionTypes))
    for g in groups:
        for s in sessions:
            dataFile = h5py.File(os.path.expanduser('~/Documents/research/data/spikesorting/hmm/p=1e-20/%sg%.4d.hdf5' % (s,g)),'r')
            try:
                for c in dataFile['unitTimePoints'].keys():
                    isi = np.log(np.diff(dataFile['unitTimePoints'][c][:]/(samplingRate/1000)))
                    cn = 'g%dc%d' % (g,int(c))
                    if cn in ISIs:
                        ISIs[cn]['%s' %(s,)] = isi
                    else:
                        ISIs[cn] = {'%s' %(s,): isi}
            finally:
                dataFile.close()
        
    i = 1
    ncells = len(ISIs.keys())
    for c in ISIs.keys():
        ax = Subplot(fig,1,ncells,i)
        formatAxis(ax)
        fig.add_axes(ax)
        ax.set_title(c)
        for k,v in ISIs[c].items():
            if sessionTypes != None:
                L = sessionTypes[k]
            else:
                L = k
            n,b = np.histogram(v,bins=20,normed=True)
            plt.plot(b[:-1],n,label=L)
        i+=1
        ax.set_xlabel('ISI [ms]')
        xl,xh = int(np.round((b[0]-0.5)*2))/2,int(np.round((b[-1]+0.5)*2))/2
        xl = -0.5
        dx = np.round(10.0*(xh-xl)/4.0)/10
        xt_ = np.arange(xl,xh+1,dx)
        ax.set_xticks(xt_)
        ax.set_xticklabels(map(lambda s: r'$10^{%.1f}$' % (s,),xt_))

    fig.axes[-1].legend()
    if save:
        if fname == None:
            fname = os.path.expanduser('~/Documents/research/figures/isi_comparison.pdf')
        fig.savefig(fname,bbox='tight')
Exemple #5
0
    def setup_axes1(self, fig, T_ticks, subplotshape=None):
        """
        A simple one.
        """
        deg = -45.
        self.tr = Affine2D().rotate_deg(deg)

        theta_ticks = []  #np.arange(theta_min, theta_max, d_T)

        grid_helper = GridHelperCurveLinear(
            self.tr,
            grid_locator1=FixedLocator(T_ticks),
            grid_locator2=FixedLocator(theta_ticks))

        if subplotshape is None:
            subplotshape = (1, 1, 1)

        ax1 = Subplot(fig, *subplotshape, grid_helper=grid_helper)
        # ax1 will have a ticks and gridlines defined by the given
        # transform (+ transData of the Axes). Note that the transform of
        # the Axes itself (i.e., transData) is not affected by the given
        # transform.

        fig.add_subplot(ax1)

        # SW, SE, NE, NW
        corners = np.array([[-25., -20.], [30., 40.], [-40., 120.],
                            [-105., 60.]])
        corners_t = self._tf(corners[:, 0], corners[:, 1])

        # ax1.set_aspect(1.)
        x_min, x_max = self.x_range
        ax1.set_xlim(x_min, x_max)
        ax1.set_ylim(*self.y_range)
        ax1.set_xlabel('Temperature [C]')

        ax1.set_aspect(1)

        #ax1.axis["t"]=ax1.new_floating_axis(0, 0.)
        #T_axis = ax1.axis['t']
        #theta_axis = ax1.axis["t2"]=ax1.new_floating_axis(1, 0.)

        # plot.draw()
        # plot.show()
        self.ax1 = ax1
Exemple #6
0
    def setup_content(self):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, axisbg=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.update()
Exemple #7
0
def standard_axis(fig,
                  subplot,
                  sharex=None,
                  sharey=None,
                  hasx=False,
                  hasy=True):

    sys.stderr.write("This method is deprecated. "
                     "Use stfio_plot.StandardAxis instead.\n")
    try:
        iter(subplot)
        if isinstance(subplot, matplotlib.gridspec.GridSpec):
            ax1 = Subplot(fig,
                          subplot,
                          frameon=False,
                          sharex=sharex,
                          sharey=sharey)
        else:
            ax1 = Subplot(fig,
                          subplot[0],
                          subplot[1],
                          subplot[2],
                          frameon=False,
                          sharex=sharex,
                          sharey=sharey)
    except:
        ax1 = Subplot(fig,
                      subplot,
                      frameon=False,
                      sharex=sharex,
                      sharey=sharey)

    fig.add_axes(ax1)
    ax1.axis["right"].set_visible(False)
    ax1.axis["top"].set_visible(False)
    if not hasx:
        ax1.axis["bottom"].set_visible(False)
    if not hasy:
        ax1.axis["left"].set_visible(False)

    return ax1
Exemple #8
0
    def setup_content(self, status_callback, marker_callback):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, facecolor=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.mtc = MotionTracker(self, status_callback)
        self.cc = ClickCatcher(self, marker_callback)
Exemple #9
0
def plotXcorr(qdata,save=False,fname='hmmSortingUnits.pdf'):

    unitTimePoints = qdata['unitTimePoints']
    samplingRate = qdata.get('samplingRate',30000.0)
    units = unitTimePoints.keys()
    nunits = len(units)
    xsize = max(10,nunits*2)
    fig = plt.figure(figsize=(xsize,(6.0/8)*xsize) )
    fig.subplots_adjust(left=0.03,right=0.97,bottom=0.03,top=0.97)
    i = 1
    if not 'XCorr' in qdata:
        if isinstance(qdata,dict):
            qdata['XCorr'] = {}
        else:
            qdata.create_group('XCorr')
    for k1 in xrange(len(units)-1) :
        if not units[k1] in qdata['XCorr']:
            qdata['XCorr'].create_group(units[k1])
        for k2 in xrange(k1+1,len(units)):
            if not units[k2] in qdata['XCorr'][units[k1]]:
                T1 = unitTimePoints[units[k1]][:]/(samplingRate/1000)
                T2 = unitTimePoints[units[k2]][:]/(samplingRate/1000)
                #compute differences less than 50 ms
                C = pdist_threshold2(T1,T2,50)
                qdata['XCorr'][units[k1]].create_dataset(units[k2],data=C,compression=2,fletcher32=True,shuffle=True)
            else:
                C = qdata['XCorr'][units[k1]][units[k2]][:]
            n,b = np.histogram(C,np.arange(-50,50),normed=True)
            ax = Subplot(fig,nunits-1,nunits,k1*nunits+k2) 
            fig.add_axes(ax)
            formatAxis(ax)
            ax.plot(b[:-1],n,'k')
            ax.fill_betweenx([0,n.max()],-1.0,1.0,color='r',alpha=0.3)
            if not (k1 == len(units)-2 and k2 == len(units)-1):
                ax.set_xticklabels('')
                ax.set_yticklabels('')
    if save:
        fig.savefig(os.path.expanduser('~/Documents/research/figures/SpikeSorting/hmm/%s' %( fname,)),bbox='tight') 
    else:
        plt.draw()
Exemple #10
0
    def create_axes_nonorthogonal(self, transform):
        self.clear_figure()
        self.set_nonorthogonal_transform(transform)
        self.ax = CurveLinearSubPlot(self.fig,
                                     1,
                                     1,
                                     1,
                                     grid_helper=GridHelperCurveLinear(
                                         (self.nonortho_tr, transform.inv_tr)))
        self.set_grid_on()
        self.fig.add_subplot(self.ax)
        self.plot_MDH = self.plot_MDH_nonorthogonal

        self.canvas.draw_idle()
Exemple #11
0
    def setup_axes1(self, fig, T_ticks, subplotshape=None):
        """
        A simple one.
        """
        deg = -45.
        self.tr = Affine2D().rotate_deg(deg)

        theta_ticks = [] #np.arange(theta_min, theta_max, d_T)

        grid_helper = GridHelperCurveLinear(self.tr, grid_locator1=FixedLocator(T_ticks), grid_locator2=FixedLocator(theta_ticks))

        if subplotshape is None:
            subplotshape = (1,1,1)

        ax1 = Subplot(fig, *subplotshape, grid_helper=grid_helper)
        # ax1 will have a ticks and gridlines defined by the given
        # transform (+ transData of the Axes). Note that the transform of
        # the Axes itself (i.e., transData) is not affected by the given
        # transform.

        fig.add_subplot(ax1)


        # SW, SE, NE, NW
        corners = np.array([[-25., -20.], [30., 40.], [-40., 120.], [-105., 60.]])
        corners_t = self._tf(corners[:,0], corners[:,1])

        # ax1.set_aspect(1.)
        x_min, x_max = self.x_range
        ax1.set_xlim(x_min, x_max)
        ax1.set_ylim(*self.y_range)
        ax1.set_xlabel('Temperature [C]')

        ax1.set_aspect(1)

        #ax1.axis["t"]=ax1.new_floating_axis(0, 0.)
        #T_axis = ax1.axis['t']
        #theta_axis = ax1.axis["t2"]=ax1.new_floating_axis(1, 0.)
        
        # plot.draw()
        # plot.show()
        self.ax1 = ax1
Exemple #12
0
    def create_axes_nonorthogonal(self, transform):
        self.clear_figure()
        self.set_nonorthogonal_transform(transform)
        self.ax = CurveLinearSubPlot(self.fig,
                                     1,
                                     1,
                                     1,
                                     grid_helper=GridHelperCurveLinear(
                                         (transform.tr, transform.inv_tr)))
        # don't redraw on zoom as the data is rebinned and has to be redrawn again anyway
        self.enable_zoom_on_mouse_scroll(redraw=False)
        self.set_grid_on()
        self.fig.add_subplot(self.ax)
        self.plot_MDH = self.plot_MDH_nonorthogonal

        self.canvas.draw_idle()
Exemple #13
0
def plot_hpxmap_hist(hpxmap,
                     raRange=[-180, 180],
                     decRange=[-90, 90],
                     lonRef=0.0,
                     cbar_kwargs=dict(),
                     hpxmap_kwargs=dict(),
                     hist_kwargs=dict(),
                     fit_gaussian=False,
                     figsize=(10, 4)):

    hist_defaults = dict(peak=True)
    set_defaults(hist_kwargs, hist_defaults)

    if isinstance(hpxmap, basestring):
        hpxmap = healpy.read_map(f)

    fig = plt.figure(10, figsize=figsize)
    fig.clf()
    gridspec = plt.GridSpec(1, 3)

    bmap = FgcmBasemap(lonRef=lonRef,
                       raMin=raRange[0],
                       raMax=raRange[1],
                       decMin=decRange[0],
                       decMax=decRange[1])
    bmap.create_axes(rect=gridspec[0:2])
    im = bmap.draw_hpxmap(hpxmap, **hpxmap_kwargs)
    bmap.draw_inset_colorbar(**cbar_kwargs)
    ax1 = plt.gca()
    ax1.axis['right'].major_ticklabels.set_visible(False)
    ax1.axis['top'].major_ticklabels.set_visible(False)

    ax2 = Subplot(fig, gridspec[2])
    fig.add_subplot(ax2)
    plt.sca(ax2)
    ret = draw_hist(hpxmap, fit_gaussian=fit_gaussian, **hist_kwargs)
    ax2.yaxis.set_major_locator(MaxNLocator(6, prune='both'))
    ax2.xaxis.set_major_locator(MaxNLocator(5))
    ax2.axis['left'].major_ticklabels.set_visible(False)
    ax2.axis['right'].major_ticklabels.set_visible(True)
    ax2.axis['right'].label.set_visible(True)
    ax2.axis['right'].label.set_text(r'Normalized Area (a.u.)')
    ax2.axis['bottom'].label.set_visible(True)

    plt.subplots_adjust(bottom=0.15, top=0.95)

    return fig, [ax1, ax2], ret
Exemple #14
0
def curvelinear_test1(fig):
    """
    Grid for custom transform.
    """
    def tr(x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x, y - (2 * x)  # return x + (5 * y), (7 * y) + (3 * x)

    def inv_tr(x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x, y + (2 * x)

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
    # ax1 will have a ticks and gridlines defined by the given
    # transform (+ transData of the Axes). Note that the transform of
    # the Axes itself (i.e., transData) is not affected by the given
    # transform.

    fig.add_subplot(ax1)

    xx, yy = tr([0, 1], [0, 2])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1)
    ax1.set_xlim(-3, 3)
    ax1.set_ylim(-3, 3)

    ax1.axis["t"] = ax1.new_floating_axis(
        0, 0
    )  # first argument appears to be slope, second argument appears to be starting point on vertical
    ax1.axis["t2"] = ax1.new_floating_axis(1, 0)
    ax1.axhline(y=0, color='r')
    ax1.axvline(x=0, color='r')
    ax1.grid(True, zorder=0)
Exemple #15
0
class DGSPlannerGUI(QtGui.QWidget):
    def __init__(self, ol=None, parent=None):
        # pylint: disable=unused-argument,super-on-old-class
        super(DGSPlannerGUI, self).__init__(parent)
        #OrientedLattice
        if ValidateOL(ol):
            self.ol = ol
        else:
            self.ol = mantid.geometry.OrientedLattice()
        self.masterDict = dict()  #holds info about instrument and ranges
        self.updatedInstrument = False
        self.updatedOL = False
        self.wg = None  #workspace group
        self.instrumentWidget = InstrumentSetupWidget.InstrumentSetupWidget(
            self)
        self.setLayout(QtGui.QHBoxLayout())
        controlLayout = QtGui.QVBoxLayout()
        controlLayout.addWidget(self.instrumentWidget)
        self.ublayout = QtGui.QHBoxLayout()
        self.classic = ClassicUBInputWidget.ClassicUBInputWidget(self.ol)
        self.ublayout.addWidget(self.classic,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        self.matrix = MatrixUBInputWidget.MatrixUBInputWidget(self.ol)
        self.ublayout.addWidget(self.matrix,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        controlLayout.addLayout(self.ublayout)
        self.dimensionWidget = DimensionSelectorWidget.DimensionSelectorWidget(
            self)
        controlLayout.addWidget(self.dimensionWidget)
        plotControlLayout = QtGui.QGridLayout()
        self.plotButton = QtGui.QPushButton("Plot", self)
        self.oplotButton = QtGui.QPushButton("Overplot", self)
        self.helpButton = QtGui.QPushButton("?", self)
        self.colorLabel = QtGui.QLabel('Color by angle', self)
        self.colorButton = QtGui.QCheckBox(self)
        self.colorButton.toggle()
        self.aspectLabel = QtGui.QLabel('Aspect ratio 1:1', self)
        self.aspectButton = QtGui.QCheckBox(self)
        self.saveButton = QtGui.QPushButton("Save Figure", self)
        plotControlLayout.addWidget(self.plotButton, 0, 0)
        plotControlLayout.addWidget(self.oplotButton, 0, 1)
        plotControlLayout.addWidget(self.colorLabel, 0, 2,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.colorButton, 0, 3)
        plotControlLayout.addWidget(self.aspectLabel, 0, 4,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.aspectButton, 0, 5)
        plotControlLayout.addWidget(self.helpButton, 0, 6)
        plotControlLayout.addWidget(self.saveButton, 0, 7)
        controlLayout.addLayout(plotControlLayout)
        self.layout().addLayout(controlLayout)

        #figure
        self.figure = Figure()
        self.figure.patch.set_facecolor('white')
        self.canvas = FigureCanvas(self.figure)
        self.grid_helper = GridHelperCurveLinear((self.tr, self.inv_tr))
        self.trajfig = Subplot(self.figure,
                               1,
                               1,
                               1,
                               grid_helper=self.grid_helper)
        self.trajfig.hold(True)
        self.figure.add_subplot(self.trajfig)
        self.layout().addWidget(self.canvas)
        self.needToClear = False
        self.saveDir = ''

        #connections
        self.matrix.UBmodel.changed.connect(self.updateUB)
        self.matrix.UBmodel.changed.connect(self.classic.updateOL)
        self.classic.changed.connect(self.matrix.UBmodel.updateOL)
        self.classic.changed.connect(self.updateUB)
        self.instrumentWidget.changed.connect(self.updateParams)
        self.dimensionWidget.changed.connect(self.updateParams)
        self.plotButton.clicked.connect(self.updateFigure)
        self.oplotButton.clicked.connect(self.updateFigure)
        self.helpButton.clicked.connect(self.help)
        self.saveButton.clicked.connect(self.save)
        #force an update of values
        self.instrumentWidget.updateAll()
        self.dimensionWidget.updateChanges()
        #help
        self.assistantProcess = QtCore.QProcess(self)
        # pylint: disable=protected-access
        self.collectionFile = os.path.join(mantid._bindir,
                                           '../docs/qthelp/MantidProject.qhc')
        version = ".".join(mantid.__version__.split(".")[:2])
        self.qtUrl = 'qthelp://org.sphinx.mantidproject.' + version + '/doc/interfaces/DGSPlanner.html'
        self.externalUrl = 'http://docs.mantidproject.org/nightly/interfaces/DGSPlanner.html'
        #control for cancel button
        self.iterations = 0
        self.progress_canceled = False

    @QtCore.pyqtSlot(mantid.geometry.OrientedLattice)
    def updateUB(self, ol):
        self.ol = ol
        self.updatedOL = True
        self.trajfig.clear()

    @QtCore.pyqtSlot(dict)
    def updateParams(self, d):
        if self.sender() is self.instrumentWidget:
            self.updatedInstrument = True
        if d.has_key('dimBasis') and self.masterDict.has_key(
                'dimBasis') and d['dimBasis'] != self.masterDict['dimBasis']:
            self.needToClear = True
        if d.has_key('dimIndex') and self.masterDict.has_key(
                'dimIndex') and d['dimIndex'] != self.masterDict['dimIndex']:
            self.needToClear = True
        self.masterDict.update(copy.deepcopy(d))

    def help(self):
        try:
            import pymantidplot
            pymantidplot.proxies.showCustomInterfaceHelp('DGSPlanner')
        except ImportError:
            self.assistantProcess.close()
            self.assistantProcess.waitForFinished()
            helpapp = QtCore.QLibraryInfo.location(
                QtCore.QLibraryInfo.BinariesPath) + QtCore.QDir.separator()
            helpapp += 'assistant'
            args = [
                '-enableRemoteControl', '-collectionFile', self.collectionFile,
                '-showUrl', self.qtUrl
            ]
            if os.path.isfile(helpapp):
                self.assistantProcess.close()
                self.assistantProcess.waitForFinished()
                self.assistantProcess.start(helpapp, args)
            else:
                QtGui.QDesktopServices.openUrl(QtCore.QUrl(self.externalUrl))

    def closeEvent(self, event):
        self.assistantProcess.close()
        self.assistantProcess.waitForFinished()
        event.accept()

    # pylint: disable=too-many-locals
    def updateFigure(self):
        # pylint: disable=too-many-branches
        if self.updatedInstrument or self.progress_canceled:
            self.progress_canceled = False
            #get goniometer settings first
            gonioAxis0values = numpy.arange(
                self.masterDict['gonioMinvals'][0],
                self.masterDict['gonioMaxvals'][0] +
                0.1 * self.masterDict['gonioSteps'][0],
                self.masterDict['gonioSteps'][0])
            gonioAxis1values = numpy.arange(
                self.masterDict['gonioMinvals'][1],
                self.masterDict['gonioMaxvals'][1] +
                0.1 * self.masterDict['gonioSteps'][1],
                self.masterDict['gonioSteps'][1])
            gonioAxis2values = numpy.arange(
                self.masterDict['gonioMinvals'][2],
                self.masterDict['gonioMaxvals'][2] +
                0.1 * self.masterDict['gonioSteps'][2],
                self.masterDict['gonioSteps'][2])
            self.iterations = len(gonioAxis0values) * len(
                gonioAxis1values) * len(gonioAxis2values)
            if self.iterations > 10:
                reply = QtGui.QMessageBox.warning(
                    self, 'Goniometer',
                    "More than 10 goniometer settings. This might be long.\n"
                    "Are you sure you want to proceed?",
                    QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                    QtGui.QMessageBox.No)
                if reply == QtGui.QMessageBox.No:
                    return
            if self.wg != None:
                mantid.simpleapi.DeleteWorkspace(self.wg)
            mantid.simpleapi.LoadEmptyInstrument(
                mantid.api.ExperimentInfo.getInstrumentFilename(
                    self.masterDict['instrument']),
                OutputWorkspace="__temp_instrument")
            if self.masterDict['instrument'] == 'HYSPEC':
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",
                                              LogName='msd',
                                              LogText='1798.5',
                                              LogType='Number Series')
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",
                                              LogName='s2',
                                              LogText=str(
                                                  self.masterDict['S2']),
                                              LogType='Number Series')
                mantid.simpleapi.LoadInstrument(Workspace="__temp_instrument",
                                                RewriteSpectraMap=True,
                                                InstrumentName="HYSPEC")
            #masking
            if self.masterDict.has_key('maskFilename') and len(
                    self.masterDict['maskFilename'].strip()) > 0:
                try:
                    __maskWS = mantid.simpleapi.Load(
                        self.masterDict['maskFilename'])
                    mantid.simpleapi.MaskDetectors(
                        Workspace="__temp_instrument",
                        MaskedWorkspace=__maskWS)
                except (ValueError, RuntimeError) as e:
                    reply = QtGui.QMessageBox.critical(
                        self, 'Error',
                        "The following error has occured in loading the mask:\n"
                        + str(e) + "\nDo you want to continue without mask?",
                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                        QtGui.QMessageBox.No)
                    if reply == QtGui.QMessageBox.No:
                        return
            if self.masterDict['makeFast']:
                sp = range(
                    mantid.mtd["__temp_instrument"].getNumberHistograms())
                tomask = sp[::4] + sp[1::4] + sp[2::4]
                mantid.simpleapi.MaskDetectors("__temp_instrument",
                                               SpectraList=tomask)
            i = 0
            groupingStrings = []
            progressDialog = QtGui.QProgressDialog(self)
            progressDialog.setMinimumDuration(0)
            progressDialog.setCancelButtonText("&Cancel")
            progressDialog.setRange(0, self.iterations)
            progressDialog.setWindowTitle("DGSPlanner progress")
            for g0 in gonioAxis0values:
                for g1 in gonioAxis1values:
                    for g2 in gonioAxis2values:
                        name = "__temp_instrument" + str(i)
                        i += 1
                        progressDialog.setValue(i)
                        progressDialog.setLabelText(
                            "Creating workspace %d of %d..." %
                            (i, self.iterations))
                        QtGui.qApp.processEvents()
                        if progressDialog.wasCanceled():
                            self.progress_canceled = True
                            progressDialog.close()
                            return
                        groupingStrings.append(name)
                        mantid.simpleapi.CloneWorkspace("__temp_instrument",
                                                        OutputWorkspace=name)
                        mantid.simpleapi.SetGoniometer(
                            Workspace=name,
                            Axis0=str(g0) + "," +
                            self.masterDict['gonioDirs'][0] + "," +
                            str(self.masterDict['gonioSenses'][0]),
                            Axis1=str(g1) + "," +
                            self.masterDict['gonioDirs'][1] + "," +
                            str(self.masterDict['gonioSenses'][1]),
                            Axis2=str(g2) + "," +
                            self.masterDict['gonioDirs'][2] + "," +
                            str(self.masterDict['gonioSenses'][2]))
            progressDialog.close()
            mantid.simpleapi.DeleteWorkspace("__temp_instrument")
            self.wg = mantid.simpleapi.GroupWorkspaces(
                groupingStrings, OutputWorkspace="__temp_instrument")
            self.updatedInstrument = False
        #set the UB
        if self.updatedOL or not self.wg[0].sample().hasOrientedLattice():
            mantid.simpleapi.SetUB(self.wg, UB=self.ol.getUB())
            self.updatedOL = False
        #calculate coverage
        dimensions = ['Q1', 'Q2', 'Q3', 'DeltaE']
        progressDialog = QtGui.QProgressDialog(self)
        progressDialog.setMinimumDuration(0)
        progressDialog.setCancelButtonText("&Cancel")
        progressDialog.setRange(0, self.iterations)
        progressDialog.setWindowTitle("DGSPlanner progress")
        for i in range(self.iterations):
            progressDialog.setValue(i)
            progressDialog.setLabelText("Calculating orientation %d of %d..." %
                                        (i, self.iterations))
            QtGui.qApp.processEvents()
            if progressDialog.wasCanceled():
                self.progress_canceled = True
                progressDialog.close()
                return

            __mdws = mantid.simpleapi.CalculateCoverageDGS(
                self.wg[i],
                Q1Basis=self.masterDict['dimBasis'][0],
                Q2Basis=self.masterDict['dimBasis'][1],
                Q3Basis=self.masterDict['dimBasis'][2],
                IncidentEnergy=self.masterDict['Ei'],
                Dimension1=dimensions[self.masterDict['dimIndex'][0]],
                Dimension1Min=float2Input(self.masterDict['dimMin'][0]),
                Dimension1Max=float2Input(self.masterDict['dimMax'][0]),
                Dimension1Step=float2Input(self.masterDict['dimStep'][0]),
                Dimension2=dimensions[self.masterDict['dimIndex'][1]],
                Dimension2Min=float2Input(self.masterDict['dimMin'][1]),
                Dimension2Max=float2Input(self.masterDict['dimMax'][1]),
                Dimension2Step=float2Input(self.masterDict['dimStep'][1]),
                Dimension3=dimensions[self.masterDict['dimIndex'][2]],
                Dimension3Min=float2Input(self.masterDict['dimMin'][2]),
                Dimension3Max=float2Input(self.masterDict['dimMax'][2]),
                Dimension4=dimensions[self.masterDict['dimIndex'][3]],
                Dimension4Min=float2Input(self.masterDict['dimMin'][3]),
                Dimension4Max=float2Input(self.masterDict['dimMax'][3]))

            if i == 0:
                intensity = __mdws.getSignalArray(
                )[:, :, 0, 0] * 1.  #to make it writeable
            else:
                if self.colorButton.isChecked():
                    tempintensity = __mdws.getSignalArray()[:, :, 0, 0]
                    intensity[numpy.where(tempintensity > 0)] = i + 1.
                else:
                    tempintensity = __mdws.getSignalArray()[:, :, 0, 0]
                    intensity[numpy.where(tempintensity > 0)] = 1.
        progressDialog.close()
        x = numpy.linspace(
            __mdws.getDimension(0).getMinimum(),
            __mdws.getDimension(0).getMaximum(), intensity.shape[0])
        y = numpy.linspace(
            __mdws.getDimension(1).getMinimum(),
            __mdws.getDimension(1).getMaximum(), intensity.shape[1])
        Y, X = numpy.meshgrid(y, x)
        xx, yy = self.tr(X, Y)
        Z = numpy.ma.masked_array(intensity, intensity == 0)
        Z = Z[:-1, :-1]
        #plotting
        if self.sender() is self.plotButton or self.needToClear:
            self.figure.clear()
            self.trajfig.clear()
            self.figure.add_subplot(self.trajfig)
            self.needToClear = False
        self.trajfig.pcolorfast(xx, yy, Z)

        if self.aspectButton.isChecked():
            self.trajfig.set_aspect(1.)
        else:
            self.trajfig.set_aspect('auto')
        self.trajfig.set_xlabel(self.masterDict['dimNames'][0])
        self.trajfig.set_ylabel(self.masterDict['dimNames'][1])
        self.trajfig.grid(True)
        self.canvas.draw()
        mantid.simpleapi.DeleteWorkspace(__mdws)

    def save(self):
        fileName = str(
            QtGui.QFileDialog.getSaveFileName(self, 'Save Plot', self.saveDir,
                                              '*.png'))
        data = "Instrument " + self.masterDict['instrument'] + '\n'
        if self.masterDict['instrument'] == 'HYSPEC':
            data += "S2 = " + str(self.masterDict['S2']) + '\n'
        data += "Ei = " + str(self.masterDict['Ei']) + ' meV\n'
        data += "Goniometer values:\n"
        gonioAxis0values = numpy.arange(
            self.masterDict['gonioMinvals'][0],
            self.masterDict['gonioMaxvals'][0] +
            0.1 * self.masterDict['gonioSteps'][0],
            self.masterDict['gonioSteps'][0])
        gonioAxis1values = numpy.arange(
            self.masterDict['gonioMinvals'][1],
            self.masterDict['gonioMaxvals'][1] +
            0.1 * self.masterDict['gonioSteps'][1],
            self.masterDict['gonioSteps'][1])
        gonioAxis2values = numpy.arange(
            self.masterDict['gonioMinvals'][2],
            self.masterDict['gonioMaxvals'][2] +
            0.1 * self.masterDict['gonioSteps'][2],
            self.masterDict['gonioSteps'][2])
        for g0 in gonioAxis0values:
            for g1 in gonioAxis1values:
                for g2 in gonioAxis2values:
                    data += "    " + self.masterDict['gonioLabels'][
                        0] + " = " + str(g0)
                    data += "    " + self.masterDict['gonioLabels'][
                        1] + " = " + str(g1)
                    data += "    " + self.masterDict['gonioLabels'][
                        2] + " = " + str(g2) + '\n'
        data += "Lattice parameters:\n"
        data += "    a = " + str(self.ol.a()) + "    b = " + str(
            self.ol.b()) + "    c = " + str(self.ol.c()) + '\n'
        data += "    alpha = " + str(self.ol.alpha()) + "    beta = " + str(
            self.ol.beta()) + "    gamma = " + str(self.ol.gamma()) + '\n'
        data += "Orientation vectors:\n"
        data += "    u = " + str(self.ol.getuVector()) + '\n'
        data += "    v = " + str(self.ol.getvVector()) + '\n'
        data+="Integrated "+self.masterDict['dimNames'][2]+" between "+\
              str(self.masterDict['dimMin'][2])+" and "+str(self.masterDict['dimMax'][2])+'\n'
        data+="Integrated "+self.masterDict['dimNames'][3]+" between "+\
              str(self.masterDict['dimMin'][3])+" and "+str(self.masterDict['dimMax'][3])+'\n'

        info = self.figure.text(0.2, 0, data, verticalalignment='top')
        self.figure.savefig(fileName,
                            bbox_inches='tight',
                            additional_artists=info)
        self.saveDir = os.path.dirname(fileName)

    def tr(self, x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        #one of the axes is energy
        if self.masterDict['dimIndex'][0] == 3 or self.masterDict['dimIndex'][
                1] == 3:
            return x, y
        else:
            h1, k1, l1 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][0]].split(','))
            h2, k2, l2 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][1]].split(','))
            angle = numpy.radians(self.ol.recAngle(h1, k1, l1, h2, k2, l2))
            return 1. * x + numpy.cos(angle) * y, numpy.sin(angle) * y

    def inv_tr(self, x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        #one of the axes is energy
        if self.masterDict['dimIndex'][0] == 3 or self.masterDict['dimIndex'][
                1] == 3:
            return x, y
        else:
            h1, k1, l1 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][0]].split(','))
            h2, k2, l2 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][1]].split(','))
            angle = numpy.radians(self.ol.recAngle(h1, k1, l1, h2, k2, l2))
            return 1. * x - y / numpy.tan(angle), y / numpy.sin(angle)
Exemple #16
0
    def __init__(self, parent=None, window_flags=None, ol=None):
        # pylint: disable=unused-argument,super-on-old-class
        super(DGSPlannerGUI, self).__init__(parent)
        if window_flags:
            self.setWindowFlags(window_flags)
        # OrientedLattice
        if ValidateOL(ol):
            self.ol = ol
        else:
            self.ol = mantid.geometry.OrientedLattice()
        self.masterDict = dict()  # holds info about instrument and ranges
        self.updatedInstrument = False
        self.instrumentWAND = False
        self.updatedOL = False
        self.wg = None  # workspace group
        self.instrumentWidget = InstrumentSetupWidget.InstrumentSetupWidget(
            self)
        self.setLayout(QtWidgets.QHBoxLayout())
        controlLayout = QtWidgets.QVBoxLayout()
        geometryBox = QtWidgets.QGroupBox("Instrument Geometry")
        plotBox = QtWidgets.QGroupBox("Plot Axes")
        geometryBoxLayout = QtWidgets.QVBoxLayout()
        geometryBoxLayout.addWidget(self.instrumentWidget)
        geometryBox.setLayout(geometryBoxLayout)
        controlLayout.addWidget(geometryBox)
        self.ublayout = QtWidgets.QHBoxLayout()
        self.classic = ClassicUBInputWidget.ClassicUBInputWidget(self.ol)
        self.ublayout.addWidget(self.classic,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        self.matrix = MatrixUBInputWidget.MatrixUBInputWidget(self.ol)
        self.ublayout.addWidget(self.matrix,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        sampleBox = QtWidgets.QGroupBox("Sample")
        sampleBox.setLayout(self.ublayout)
        controlLayout.addWidget(sampleBox)
        self.dimensionWidget = DimensionSelectorWidget.DimensionSelectorWidget(
            self)
        plotBoxLayout = QtWidgets.QVBoxLayout()
        plotBoxLayout.addWidget(self.dimensionWidget)
        plotControlLayout = QtWidgets.QGridLayout()
        self.plotButton = QtWidgets.QPushButton("Plot", self)
        self.oplotButton = QtWidgets.QPushButton("Overplot", self)
        self.helpButton = QtWidgets.QPushButton("?", self)
        self.colorLabel = QtWidgets.QLabel('Color by angle', self)
        self.colorButton = QtWidgets.QCheckBox(self)
        self.colorButton.toggle()
        self.aspectLabel = QtWidgets.QLabel('Aspect ratio 1:1', self)
        self.aspectButton = QtWidgets.QCheckBox(self)
        self.saveButton = QtWidgets.QPushButton("Save Figure", self)
        plotControlLayout.addWidget(self.plotButton, 0, 0)
        plotControlLayout.addWidget(self.oplotButton, 0, 1)
        plotControlLayout.addWidget(self.colorLabel, 0, 2,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.colorButton, 0, 3)
        plotControlLayout.addWidget(self.aspectLabel, 0, 4,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.aspectButton, 0, 5)
        plotControlLayout.addWidget(self.helpButton, 0, 6)
        plotControlLayout.addWidget(self.saveButton, 0, 7)
        plotBoxLayout.addLayout(plotControlLayout)
        plotBox = QtWidgets.QGroupBox("Plot Axes")
        plotBox.setLayout(plotBoxLayout)
        controlLayout.addWidget(plotBox)
        self.layout().addLayout(controlLayout)

        # figure
        self.figure = Figure()
        self.figure.patch.set_facecolor('white')
        self.canvas = FigureCanvas(self.figure)
        self.grid_helper = GridHelperCurveLinear((self.tr, self.inv_tr))
        self.trajfig = Subplot(self.figure,
                               1,
                               1,
                               1,
                               grid_helper=self.grid_helper)
        if matplotlib.compare_versions('2.1.0', matplotlib.__version__):
            self.trajfig.hold(
                True)  # hold is deprecated since 2.1.0, true by default
        self.figure.add_subplot(self.trajfig)
        self.toolbar = MantidNavigationToolbar(self.canvas, self)
        figureLayout = QtWidgets.QVBoxLayout()
        figureLayout.addWidget(self.toolbar, 0)
        figureLayout.addWidget(self.canvas, 1)
        self.layout().addLayout(figureLayout)
        self.needToClear = False
        self.saveDir = ''

        # connections
        self.matrix.UBmodel.changed.connect(self.updateUB)
        self.matrix.UBmodel.changed.connect(self.classic.updateOL)
        self.classic.changed.connect(self.matrix.UBmodel.updateOL)
        self.classic.changed.connect(self.updateUB)
        self.instrumentWidget.changed.connect(self.updateParams)
        self.instrumentWidget.getInstrumentComboBox().activated[str].connect(
            self.instrumentUpdateEvent)
        self.instrumentWidget.getEditEi().textChanged.connect(
            self.eiWavelengthUpdateEvent)
        self.dimensionWidget.changed.connect(self.updateParams)
        self.plotButton.clicked.connect(self.updateFigure)
        self.oplotButton.clicked.connect(self.updateFigure)
        self.helpButton.clicked.connect(self.help)
        self.saveButton.clicked.connect(self.save)
        # force an update of values
        self.instrumentWidget.updateAll()
        self.dimensionWidget.updateChanges()
        # help
        self.assistant_process = QtCore.QProcess(self)
        # pylint: disable=protected-access
        self.mantidplot_name = 'DGS Planner'
        # control for cancel button
        self.iterations = 0
        self.progress_canceled = False

        # register startup
        mantid.UsageService.registerFeatureUsage(
            mantid.kernel.FeatureType.Interface, "DGSPlanner", False)
Exemple #17
0
    # http://matplotlib.org/examples/axes_grid/demo_curvelinear_grid.html
    from mpl_toolkits.axisartist import Subplot
    from mpl_toolkits.axisartist.grid_helper_curvelinear import \
        GridHelperCurveLinear

    def tr(x, y):  # source (data) to target (rectilinear plot) coordinates
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x + 0.2 * y, y - x

    def inv_tr(x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x - 0.2 * y, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax6 = Subplot(fig, nrow, ncol, 6, grid_helper=grid_helper)
    fig.add_subplot(ax6)
    ax6.set_title('non-ortho axes')

    xx, yy = tr([3, 6], [5.0, 10.])
    ax6.plot(xx, yy)

    ax6.set_aspect(1.)
    ax6.set_xlim(0, 10.)
    ax6.set_ylim(0, 10.)

    ax6.axis["t"] = ax6.new_floating_axis(0, 3.)
    ax6.axis["t2"] = ax6.new_floating_axis(1, 7.)
    ax6.grid(True)

    plt.show()
Exemple #18
0
def curvelinear_test1(fig):
    """
    grid for custom transform.
    """
    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y - x

    def inv_tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    # ax1 will have a ticks and gridlines defined by the given
    # transform (+ transData of the Axes). Note that the transform of
    # the Axes itself (i.e., transData) is not affected by the given
    # transform.

    fig.add_subplot(ax1)

    xx, yy = tr([3, 6], [5.0, 10.])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1.)
    ax1.set_xlim(0, 10.)
    ax1.set_ylim(0, 10.)

    ax1.axis["t"] = ax1.new_floating_axis(0, 3.)
    ax1.axis["t2"] = ax1.new_floating_axis(1, 7.)
    ax1.grid(True, zorder=0)
Exemple #19
0
    def __init__(self,ol=None,parent=None):
        # pylint: disable=unused-argument,super-on-old-class
        super(DGSPlannerGUI,self).__init__(parent)
        #OrientedLattice
        if ValidateOL(ol):
            self.ol=ol
        else:
            self.ol=mantid.geometry.OrientedLattice()
        self.masterDict=dict() #holds info about instrument and ranges
        self.updatedInstrument=False
        self.updatedOL=False
        self.wg=None #workspace group
        self.instrumentWidget=InstrumentSetupWidget.InstrumentSetupWidget(self)
        self.setLayout(QtGui.QHBoxLayout())
        controlLayout=QtGui.QVBoxLayout()
        controlLayout.addWidget(self.instrumentWidget)
        self.ublayout=QtGui.QHBoxLayout()
        self.classic=ClassicUBInputWidget.ClassicUBInputWidget(self.ol)
        self.ublayout.addWidget(self.classic,alignment=QtCore.Qt.AlignTop,stretch=1)
        self.matrix=MatrixUBInputWidget.MatrixUBInputWidget(self.ol)
        self.ublayout.addWidget(self.matrix,alignment=QtCore.Qt.AlignTop,stretch=1)
        controlLayout.addLayout(self.ublayout)
        self.dimensionWidget=DimensionSelectorWidget.DimensionSelectorWidget(self)
        controlLayout.addWidget(self.dimensionWidget)
        plotControlLayout=QtGui.QGridLayout()
        self.plotButton=QtGui.QPushButton("Plot",self)
        self.oplotButton=QtGui.QPushButton("Overplot",self)
        self.helpButton=QtGui.QPushButton("?",self)
        self.colorLabel=QtGui.QLabel('Color by angle',self)
        self.colorButton=QtGui.QCheckBox(self)
        self.colorButton.toggle()
        self.aspectLabel=QtGui.QLabel('Aspect ratio 1:1',self)
        self.aspectButton=QtGui.QCheckBox(self)
        self.saveButton=QtGui.QPushButton("Save Figure",self)
        plotControlLayout.addWidget(self.plotButton,0,0)
        plotControlLayout.addWidget(self.oplotButton,0,1)
        plotControlLayout.addWidget(self.colorLabel,0,2,QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.colorButton,0,3)
        plotControlLayout.addWidget(self.aspectLabel,0,4,QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.aspectButton,0,5)
        plotControlLayout.addWidget(self.helpButton,0,6)
        plotControlLayout.addWidget(self.saveButton,0,7)
        controlLayout.addLayout(plotControlLayout)
        self.layout().addLayout(controlLayout)

        #figure
        self.figure=Figure()
        self.figure.patch.set_facecolor('white')
        self.canvas=FigureCanvas(self.figure)
        self.grid_helper = GridHelperCurveLinear((self.tr, self.inv_tr))
        self.trajfig = Subplot(self.figure, 1, 1, 1, grid_helper=self.grid_helper)
        self.trajfig.hold(True)
        self.figure.add_subplot(self.trajfig)
        self.layout().addWidget(self.canvas)
        self.needToClear=False
        self.saveDir=''

        #connections
        self.matrix.UBmodel.changed.connect(self.updateUB)
        self.matrix.UBmodel.changed.connect(self.classic.updateOL)
        self.classic.changed.connect(self.matrix.UBmodel.updateOL)
        self.classic.changed.connect(self.updateUB)
        self.instrumentWidget.changed.connect(self.updateParams)
        self.dimensionWidget.changed.connect(self.updateParams)
        self.plotButton.clicked.connect(self.updateFigure)
        self.oplotButton.clicked.connect(self.updateFigure)
        self.helpButton.clicked.connect(self.help)
        self.saveButton.clicked.connect(self.save)
        #force an update of values
        self.instrumentWidget.updateAll()
        self.dimensionWidget.updateChanges()
        #help
        self.assistantProcess = QtCore.QProcess(self)
        # pylint: disable=protected-access
        self.collectionFile=os.path.join(mantid._bindir,'../docs/qthelp/MantidProject.qhc')
        version = ".".join(mantid.__version__.split(".")[:2])
        self.qtUrl='qthelp://org.sphinx.mantidproject.'+version+'/doc/interfaces/DGSPlanner.html'
        self.externalUrl='http://docs.mantidproject.org/nightly/interfaces/DGSPlanner.html'
        #control for cancel button
        self.iterations=0
        self.progress_canceled=False

        #register startup
        mantid.UsageService.registerFeatureUsage("Interface","DGSPlanner",False)
Exemple #20
0
class MainPlotController(object):
    """
        A controller for the main plot canvas.
        Sets up the widgets and has image exporting functionality.
    """

    file_filters = ("Portable Network Graphics (PNG)", "*.png"), \
                   ("Scalable Vector Graphics (SVG)", "*.svg"), \
                   ("Portable Document Format (PDF)", "*.pdf")

    _canvas = None

    @property
    def canvas(self):
        if not self._canvas:
            self.setup_figure()
            self.setup_canvas()
            self.setup_content()
        return self._canvas

    # ------------------------------------------------------------
    #      View integration getters
    # ------------------------------------------------------------
    def get_toolbar_widget(self, window):
        return NavigationToolbar(self.canvas, window)

    def get_canvas_widget(self):
        return self.canvas

    # ------------------------------------------------------------
    #      Initialization and other internals
    # ------------------------------------------------------------
    def __init__(self, status_callback, marker_callback, *args, **kwargs):
        self.setup_layout_cache()
        self.setup_figure()
        self.setup_canvas()
        self.setup_content(status_callback, marker_callback)

    def setup_layout_cache(self):
        self.position_setup = PositionSetup()
        self.labels = list()
        self.marker_lbls = list()
        self._proxies = dict()
        self.scale = 1.0
        self.stats = False
        self._last_pos = None

    def setup_figure(self):
        self.figure = Figure(dpi=72, facecolor="#FFFFFF", linewidth=0)
        self.figure.subplots_adjust(hspace=0.0, wspace=0.0)

    def setup_canvas(self):
        self._canvas = FigureCanvasGTK(self.figure)

    def setup_content(self, status_callback, marker_callback):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, facecolor=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.mtc = MotionTracker(self, status_callback)
        self.cc = ClickCatcher(self, marker_callback)

        #self.update()

    # ------------------------------------------------------------
    #      Update methods
    # ------------------------------------------------------------
    def draw(self):
        self._last_pos = self.fix_before_drawing()
        self.figure.canvas.draw()

    def fix_after_drawing(self, *args):
        _new_pos = self.fix_before_drawing()

        if _new_pos != self._last_pos:
            self._last_pos = _new_pos
            self._redraw_later()

        return False

    def _redraw_later(self):
        self.timer = self.figure.canvas.new_timer(interval=10)
        self.timer.single_shot = True
        self.timer.add_callback(lambda: self.figure.canvas.draw_idle())
        self.timer.start()

    def fix_before_drawing(self, *args):
        """
            Fixes alignment issues due to longer labels or smaller windows
            Is executed after an initial draw event, since we can then retrieve
            the actual label dimensions and shift/resize the plot accordingly.
        """
        renderer = get_renderer(self.figure)
        if not renderer or not self._canvas.get_realized():
            return False

        # Fix left side for wide specimen labels:
        if len(self.labels) > 0:
            bbox = self._get_joint_bbox(self.labels, renderer)
            if bbox is not None:
                self.position_setup.left = self.position_setup.default_left + bbox.width
        # Fix top for high marker labels:
        if len(self.marker_lbls) > 0:
            bbox = self._get_joint_bbox(
                [label for label, flag, _ in self.marker_lbls if flag],
                renderer)
            if bbox is not None:
                self.position_setup.top = self.position_setup.default_top - bbox.height
        # Fix bottom for x-axis label:
        bottom_label = self.plot.axis["bottom"].label
        if bottom_label is not None:
            bbox = self._get_joint_bbox([bottom_label], renderer)
            if bbox is not None:
                self.position_setup.bottom = self.position_setup.default_bottom + (
                    bbox.ymax - bbox.ymin) * 2.0  # somehow we need this?

        # Calculate new plot position & set it:
        plot_pos = self.position_setup.position
        self.plot.set_position(plot_pos)

        # Adjust specimen label position
        for label in self.labels:
            label.set_x(plot_pos[0] - 0.025)

        # Adjust marker label position
        for label, flag, y_offset in self.marker_lbls:
            if flag:
                newy = plot_pos[1] + plot_pos[3] + y_offset - 0.025
                label.set_y(newy)

        _new_pos = self.position_setup.to_string()
        return _new_pos

    def update(self, clear=False, project=None, specimens=None):
        """
            Updates the entire plot with the given information.
        """
        if clear: self.plot.cla()

        if project and specimens:
            self.labels, self.marker_lbls = plot_specimens(
                self.plot, self.position_setup, self.cc, project, specimens)
            # get mixtures for the selected specimens:
            plot_mixtures(self.plot, project, [
                mixture for mixture in project.mixtures
                if any(specimen in mixture.specimens for specimen in specimens)
            ])

        update_axes(self.plot, self.position_setup, project, specimens)

        self.draw()

    # ------------------------------------------------------------
    #      Plot position and size calculations
    # ------------------------------------------------------------
    def _get_joint_bbox(self, container, renderer):
        bboxes = []
        try:
            for text in container:
                bbox = text.get_window_extent(renderer=renderer)
                # the figure transform goes from relative coords->pixels and we
                # want the inverse of that
                bboxi = bbox.inverse_transformed(self.figure.transFigure)
                bboxes.append(bboxi)
        except (RuntimeError, ValueError):
            logger.exception(
                "Caught unhandled exception when joining boundig boxes")
            return None  # don't continue
        # this is the bbox that bounds all the bboxes, again in relative
        # figure coords
        if len(bboxes) > 0:
            bbox = transforms.Bbox.union(bboxes)
            return bbox
        else:
            return None

    # ------------------------------------------------------------
    #      Graph exporting
    # ------------------------------------------------------------
    def save(self,
             parent=None,
             current_name="graph",
             size="auto",
             num_specimens=1,
             offset=0.75):
        """
            Displays a save dialog to export an image from the current plot.
        """
        # Parse arguments:
        width, height = 0, 0
        if size == "auto":
            descr, width, height, dpi = settings.OUTPUT_PRESETS[0]
        else:
            width, height, dpi = list(
                map(float,
                    size.replace("@", "x").split("x")))

        # Load gui:
        builder = Gtk.Builder()
        builder.add_from_file(
            resource_filename("pyxrd.specimen", "glade/save_graph_size.glade")
        )  # FIXME move this to this namespace!!
        size_expander = builder.get_object("size_expander")
        cmb_presets = builder.get_object("cmb_presets")

        # Setup combo with presets:
        cmb_store = Gtk.ListStore(str, int, int, float)
        for row in settings.OUTPUT_PRESETS:
            cmb_store.append(row)
        cmb_presets.clear()
        cmb_presets.set_model(cmb_store)
        cell = Gtk.CellRendererText()
        cmb_presets.pack_start(cell, True)
        cmb_presets.add_attribute(cell, 'text', 0)

        def on_cmb_changed(cmb, *args):
            itr = cmb.get_active_iter()
            w, h, d = cmb_store.get(itr, 1, 2, 3)
            entry_w.set_text(str(w))
            entry_h.set_text(str(h))
            entry_dpi.set_text(str(d))

        cmb_presets.connect('changed', on_cmb_changed)

        # Setup input boxes:
        entry_w = builder.get_object("entry_width")
        entry_h = builder.get_object("entry_height")
        entry_dpi = builder.get_object("entry_dpi")
        entry_w.set_text(str(width))
        entry_h.set_text(str(height))
        entry_dpi.set_text(str(dpi))

        # What to do when the user wants to save this:
        def on_accept(dialog):
            # Get the width, height & dpi
            width = float(entry_w.get_text())
            height = float(entry_h.get_text())
            dpi = float(entry_dpi.get_text())
            i_width, i_height = width / dpi, height / dpi
            # Save it all right!
            self.save_figure(dialog.filename, dpi, i_width, i_height)

        # Ask the user where, how and if he wants to save:
        DialogFactory.get_save_dialog(
            "Save Graph",
            parent=parent,
            filters=self.file_filters,
            current_name=current_name,
            extra_widget=size_expander).run(on_accept)

    def save_figure(self, filename, dpi, i_width, i_height):
        """
            Save the current plot
            
            Arguments:
             filename: the filename to save to (either .png, .pdf or .svg)
             dpi: Dots-Per-Inch resolution
             i_width: the width in inch
             i_height: the height in inch
        """
        # Get original settings:
        original_dpi = self.figure.get_dpi()
        original_width, original_height = self.figure.get_size_inches()
        # Set everything according to the user selection:
        self.figure.set_dpi(dpi)
        self.figure.set_size_inches((i_width, i_height))
        self.figure.canvas.draw()  # replot
        bbox_inches = matplotlib.transforms.Bbox.from_bounds(
            0, 0, i_width, i_height)
        # Save the figure:
        self.figure.savefig(filename, dpi=dpi, bbox_inches=bbox_inches)
        # Put everything back the way it was:
        self.figure.set_dpi(original_dpi)
        self.figure.set_size_inches((original_width, original_height))
        self.figure.canvas.draw()  # replot

    pass  # end of class
Exemple #21
0
class Tephigram(object):
    """
    Generate a tephigram of one or more pressure and temperature data sets.

    """

    def __init__(self, figure=None, isotherm_locator=None,
                 dry_adiabat_locator=None, anchor=None):
        """
        Initialise the tephigram transformation and plot axes.

        Kwargs:

        * figure:
            An existing :class:`matplotlib.figure.Figure` instance for the
            tephigram plot. If a figure is not provided, a new figure will
            be created by default.
        * isotherm_locator:
            A :class:`edson.Locator` instance or a numeric step size
            for the isotherm lines.
        * dry_adiabat_locator:
            A :class:`edson.Locator` instance or a numeric step size
            for the dry adiabat lines.
        * anchor:
            A sequence of two pressure, temperature pairs specifying the extent
            of the tephigram plot in terms of the bottom left hand corner and
            the top right hand corner. Pressure data points must be in units of
            mb or hPa, and temperature data points must be in units of degC.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            import os.path
            import edson
            from edson import Tephigram

            dew_point = os.path.join(edson.RESOURCES_DIR, 'tephigram', 'dews.txt')
            dry_bulb = os.path.join(edson.RESOURCES_DIR, 'tephigram', 'temps.txt')
            dew_data, temp_data = edson.loadtxt(dew_point, dry_bulb)
            dews = zip(dew_data.pressure, dew_data.temperature)
            temps = zip(temp_data.pressure, temp_data.temperature)
            tephi = Tephigram()
            tephi.plot(dews, label='Dew-point', color='blue', linewidth=2, marker='s')
            tephi.plot(temps, label='Dry-bulb', color='red', linewidth=2, marker='o')
            plt.show()

        """
        if not figure:
            # Create a default figure.
            self.figure = plt.figure(0, figsize=(9, 9))
        else:
            self.figure = figure

        # Configure the locators.
        if isotherm_locator and not isinstance(isotherm_locator, Locator):
            if not isinstance(isotherm_locator, numbers.Number):
                raise ValueError('Invalid isotherm locator')
            locator_isotherm = Locator(isotherm_locator)
        else:
            locator_isotherm = isotherm_locator

        if dry_adiabat_locator and not isinstance(dry_adiabat_locator, Locator):
            if not isinstance(dry_adiabat_locator, numbers.Number):
                raise ValueError('Invalid dry adiabat locator')
            locator_theta = Locator(dry_adiabat_locator)
        else:
            locator_theta = dry_adiabat_locator

        # Define the tephigram coordinate-system transformation.
        self.tephi_transform = transforms.TephiTransform()
        grid_helper1 = GridHelperCurveLinear(self.tephi_transform,
                                             tick_formatter1=_FormatterIsotherm(),
                                             grid_locator1=locator_isotherm,
                                             tick_formatter2=_FormatterTheta(),
                                             grid_locator2=locator_theta)
        self.axes = Subplot(self.figure, 1, 1, 1, grid_helper=grid_helper1)
        self.transform = self.tephi_transform + self.axes.transData
        self.axes.axis['isotherm'] = self.axes.new_floating_axis(1, 0)
        self.axes.axis['theta'] = self.axes.new_floating_axis(0, 0)
        self.axes.axis['left'].get_helper().nth_coord_ticks = 0
        self.axes.axis['left'].toggle(all=True)
        self.axes.axis['bottom'].get_helper().nth_coord_ticks = 1
        self.axes.axis['bottom'].toggle(all=True)
        self.axes.axis['top'].get_helper().nth_coord_ticks = 0
        self.axes.axis['top'].toggle(all=False)
        self.axes.axis['right'].get_helper().nth_coord_ticks = 1
        self.axes.axis['right'].toggle(all=True)
        self.axes.gridlines.set_linestyle('solid')

        self.figure.add_subplot(self.axes)

        # Configure default axes.
        axis = self.axes.axis['left']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('baseline')
        axis.major_ticklabels.set_rotation(135)
        axis = self.axes.axis['right']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('baseline')
        axis.major_ticklabels.set_rotation(-135)
        self.axes.axis['top'].major_ticklabels.set_fontsize(10)
        axis = self.axes.axis['bottom']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_ha('left')
        axis.major_ticklabels.set_va('top')
        axis.major_ticklabels.set_rotation(-45)

        # Isotherms: lines of constant temperature (degC).
        axis = self.axes.axis['isotherm']
        axis.set_axis_direction('right')
        axis.set_axislabel_direction('-')
        axis.major_ticklabels.set_rotation(90)
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('bottom')
        axis.major_ticklabels.set_color('grey')
        axis.major_ticklabels.set_visible(False)  # turned-off

        # Dry adiabats: lines of constant potential temperature (degC).
        axis = self.axes.axis['theta']
        axis.set_axis_direction('right')
        axis.set_axislabel_direction('+')
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('bottom')
        axis.major_ticklabels.set_color('grey')
        axis.major_ticklabels.set_visible(False)  # turned-off
        axis.line.set_linewidth(3)
        axis.line.set_linestyle('--')

        # Lock down the aspect ratio.
        self.axes.set_aspect(1.)
        self.axes.grid(True)

        # Initialise the text formatter for the navigation status bar.
        self.axes.format_coord = self._status_bar

        # Factor in the tephigram transform.
        ISOBAR_TEXT['transform'] = self.transform
        WET_ADIABAT_TEXT['transform'] = self.transform
        MIXING_RATIO_TEXT['transform'] = self.transform

        # Create plot collections for the tephigram isopleths.
        func = partial(isopleths.isobar, MIN_THETA, MAX_THETA, self.axes, self.transform, ISOBAR_LINE)
        self._isobars = _PlotCollection(self.axes, ISOBAR_SPEC, MAX_PRESSURE, func, ISOBAR_TEXT,
                                        fixed=ISOBAR_FIXED, minimum=MIN_PRESSURE)

        func = partial(isopleths.wet_adiabat, MAX_PRESSURE, MIN_TEMPERATURE, self.axes, self.transform, WET_ADIABAT_LINE)
        self._wet_adiabats = _PlotCollection(self.axes, WET_ADIABAT_SPEC, MAX_WET_ADIABAT, func, WET_ADIABAT_TEXT,
                                             fixed=WET_ADIABAT_FIXED, minimum=MIN_WET_ADIABAT, xfocus=True)

        func = partial(isopleths.mixing_ratio, MIN_PRESSURE, MAX_PRESSURE, self.axes, self.transform, MIXING_RATIO_LINE)
        self._mixing_ratios = _PlotCollection(self.axes, MIXING_RATIO_SPEC, MIXING_RATIOS, func, MIXING_RATIO_TEXT,
                                              fixed=MIXING_RATIO_FIXED)

        # Initialise for the tephigram plot event handler.
        plt.connect('motion_notify_event', _handler)
        self.axes.tephigram = True
        self.axes.tephigram_original_delta_xlim = self.original_delta_xlim = DEFAULT_WIDTH
        self.axes.tephigram_transform = self.tephi_transform
        self.axes.tephigram_inverse = self.tephi_transform.inverted()
        self.axes.tephigram_isopleths = [self._isobars, self._wet_adiabats, self._mixing_ratios]

       # The tephigram profiles.
        self._profiles = []
        self.axes.tephigram_profiles = self._profiles

        # Center the plot around the anchor extent.
        self._anchor = anchor
        if self._anchor is not None:
            self._anchor = np.asarray(anchor)
            if self._anchor.ndim != 2 or self._anchor.shape[-1] != 2 or \
              len(self._anchor) != 2:
                msg = 'Invalid anchor, expecting [(bottom-left-pressure, ' \
                'bottom-left-temperature), (top-right-pressure, ' \
                'top-right-temperature)]'
                raise ValueError(msg)
            (bottom_pressure, bottom_temp), \
              (top_pressure, top_temp) = self._anchor

            if (bottom_pressure - top_pressure) < 0:
                raise ValueError('Invalid anchor pressure range')
            if (bottom_temp - top_temp) < 0:
                raise ValueError('Invalid anchor temperature range')

            self._anchor = isopleths.Profile(anchor, self.axes)
            self._anchor.plot(visible=False)
            xlim, ylim = self._calculate_extents()
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

    def plot(self, data, **kwargs):
        """
        Plot the environmental lapse rate profile of the pressure and
        temperature data points.

        The pressure and temperature data points are transformed into
        potential temperature and temperature data points before plotting.

        By default, the tephigram will automatically center the plot around
        all profiles.

        .. warning::
            Pressure data points must be in units of mb or hPa, and temperature
            data points must be in units of degC.

        Args:

        * data: pressure and temperature pair data points.

        .. note::
            All keyword arguments are passed through to
            :func:`matplotlib.pyplot.plot`.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from edson import Tephigram

            tephi = Tephigram()
            data = [[1006, 26.4], [924, 20.3], [900, 19.8],
                    [850, 14.5], [800, 12.9], [755, 8.3]]
            profile = tephi.plot(data, color='red', linestyle='--',
                                 linewidth=2, marker='o')
            barbs = [(10, 45, 900), (20, 60, 850), (25, 90, 800)]
            profile.barbs(barbs)
            plt.show()

        For associating wind barbs with an environmental lapse rate profile,
        see :meth:`~edson.isopleths.Profile.barbs`.

        """
        profile = isopleths.Profile(data, self.axes)
        profile.plot(**kwargs)
        self._profiles.append(profile)

        # Center the tephigram plot around all the profiles.
        if self._anchor is None:
            xlim, ylim = self._calculate_extents(xfactor=.25, yfactor=.05)
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

        # Refresh the tephigram plot isopleths.
        _refresh_isopleths(self.axes)

        # Show the plot legend.
        if 'label' in kwargs:
            font_properties = FontProperties(size='x-small')
            plt.legend(loc='upper left', fancybox=True, shadow=True, prop=font_properties)

        return profile

    def _status_bar(self, x_point, y_point):
        """Generate text for the interactive backend navigation status bar."""

        temperature, theta = transforms.xy_to_temperature_theta(x_point, y_point)
        pressure, _ = transforms.temperature_theta_to_pressure_temperature(temperature, theta)
        xlim = self.axes.get_xlim()
        zoom = (xlim[1] - xlim[0]) / self.original_delta_xlim
        text = "T:%.2f, theta:%.2f, phi:%.2f (zoom:%.3f)" % (float(temperature), float(theta), float(pressure), zoom)

        return text

    def _calculate_extents(self, xfactor=None, yfactor=None):
        min_x = min_y = 1e10
        max_x = max_y = -1e-10
        profiles = self._profiles

        if self._anchor is not None:
            profiles = [self._anchor]

        for profile in profiles:
            xy_points = self.tephi_transform.transform(np.concatenate((profile.temperature.reshape(-1, 1),
                                                                       profile.theta.reshape(-1, 1)),
                                                                       axis=1))
            x_points = xy_points[:, 0]
            y_points = xy_points[:, 1]
            min_x, min_y = np.min([min_x, np.min(x_points)]), np.min([min_y, np.min(y_points)])
            max_x, max_y = np.max([max_x, np.max(x_points)]), np.max([max_y, np.max(y_points)])

        if xfactor is not None:
            delta_x = max_x - min_x
            min_x, max_x = min_x - xfactor * delta_x, max_x + xfactor * delta_x

        if yfactor is not None:
            delta_y = max_y - min_y
            min_y, max_y = min_y - yfactor * delta_y, max_y + yfactor * delta_y

        return ([min_x, max_x], [min_y, max_y])
Exemple #22
0
class MainPlotController (PlotController):
    """
        A controller for the main plot canvas.
    """
    # ------------------------------------------------------------
    #      Initialization and other internals
    # ------------------------------------------------------------
    def __init__(self, app_controller, *args, **kwargs):
        self.labels = list()
        self.marker_lbls = list()
        self.scale = 1.0
        self.stats = False

        self.position_setup = PositionSetup()

        self.app_controller = app_controller
        PlotController.__init__(self, *args, **kwargs)

    def setup_content(self):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, axisbg=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.update()

    # ------------------------------------------------------------
    #      Update methods
    # ------------------------------------------------------------
    def update(self, clear=False, project=None, specimens=None):
        """
            Updates the entire plot with the given information.
        """
        if clear: self.plot.cla()

        if project and specimens:
            self.labels, self.marker_lbls = plot_specimens(
                self.plot, self.position_setup,
                project, specimens
            )
            # get mixtures for the selected specimens:
            plot_mixtures(self.plot, project, [ mixture for mixture in project.mixtures if any(specimen in mixture.specimens for specimen in specimens) ])

        update_axes(
            self.plot, self.position_setup,
            project, specimens
        )

        self.draw()

    # ------------------------------------------------------------
    #      Plot position and size calculations
    # ------------------------------------------------------------
    def _get_joint_bbox(self, container):
        renderer = self._find_renderer()
        bboxes = []
        try:
            for text in container:
                bbox = text.get_window_extent(renderer=renderer)
                # the figure transform goes from relative coords->pixels and we
                # want the inverse of that
                bboxi = bbox.inverse_transformed(self.figure.transFigure)
                bboxes.append(bboxi)
        except RuntimeError:
            logger.exception("Caught unhandled exception when joining boundig boxes")
            return None # don't continue
        # this is the bbox that bounds all the bboxes, again in relative
        # figure coords
        if len(bboxes) > 0:
            bbox = transforms.Bbox.union(bboxes)
            return bbox
        else:
            return None

    def _find_renderer(self):
        if hasattr(self.figure.canvas, "get_renderer"):
            #Some backends, such as TkAgg, have the get_renderer method, which
            #makes this easy.
            renderer = self.figure.canvas.get_renderer()
        else:
            #Others don't, but since this is called in the 'fix_after_drawing',
            # a renderer has been created, so we can get it like this:
            renderer = self.figure._cachedRenderer
        return renderer

    def fix_after_drawing(self, *args):
        """
            Fixes alignment issues due to longer labels or smaller windows
            Is executed after an initial draw event, since we can then retrieve
            the actual label dimensions and shift/resize the plot accordingly.
        """
        # Fix left side for wide specimen labels:
        if len(self.labels) > 0:
            bbox = self._get_joint_bbox(self.labels)
            self.position_setup.left = 0.05 + bbox.width
        # Fix top for high marker labels:
        if len(self.marker_lbls) > 0:
            bbox = self._get_joint_bbox([ label for label, flag, _ in self.marker_lbls if flag ])
            if bbox is not None: self.position_setup.top = 1.0 - (0.05 + bbox.height) #Figure top - marker margin
        # Fix bottom for x-axis label:
        bottom_label = self.plot.axis["bottom"].label
        if bottom_label is not None:
            bbox = self._get_joint_bbox([bottom_label])
            if bbox is not None: self.position_setup.bottom = 0.10 - min(bbox.ymin, 0.0)

        # Calculate new plot position & set it:
        plot_pos = self.position_setup.position
        self.plot.set_position(plot_pos)

        # Adjust specimen label position
        for label in self.labels:
            label.set_x(plot_pos[0] - 0.025)

        # Adjust marker label position
        for label, flag, y_offset in self.marker_lbls:
            if flag:
                label.set_y(plot_pos[1] + plot_pos[3] + y_offset - 0.025)

        self.figure.canvas.draw()

        return False

    pass # end of class
Exemple #23
0
    def __init__(self, figure=None, isotherm_locator=None,
                 dry_adiabat_locator=None, anchor=None):
        """
        Initialise the tephigram transformation and plot axes.

        Kwargs:

        * figure:
            An existing :class:`matplotlib.figure.Figure` instance for the
            tephigram plot. If a figure is not provided, a new figure will
            be created by default.
        * isotherm_locator:
            A :class:`edson.Locator` instance or a numeric step size
            for the isotherm lines.
        * dry_adiabat_locator:
            A :class:`edson.Locator` instance or a numeric step size
            for the dry adiabat lines.
        * anchor:
            A sequence of two pressure, temperature pairs specifying the extent
            of the tephigram plot in terms of the bottom left hand corner and
            the top right hand corner. Pressure data points must be in units of
            mb or hPa, and temperature data points must be in units of degC.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            import os.path
            import edson
            from edson import Tephigram

            dew_point = os.path.join(edson.RESOURCES_DIR, 'tephigram', 'dews.txt')
            dry_bulb = os.path.join(edson.RESOURCES_DIR, 'tephigram', 'temps.txt')
            dew_data, temp_data = edson.loadtxt(dew_point, dry_bulb)
            dews = zip(dew_data.pressure, dew_data.temperature)
            temps = zip(temp_data.pressure, temp_data.temperature)
            tephi = Tephigram()
            tephi.plot(dews, label='Dew-point', color='blue', linewidth=2, marker='s')
            tephi.plot(temps, label='Dry-bulb', color='red', linewidth=2, marker='o')
            plt.show()

        """
        if not figure:
            # Create a default figure.
            self.figure = plt.figure(0, figsize=(9, 9))
        else:
            self.figure = figure

        # Configure the locators.
        if isotherm_locator and not isinstance(isotherm_locator, Locator):
            if not isinstance(isotherm_locator, numbers.Number):
                raise ValueError('Invalid isotherm locator')
            locator_isotherm = Locator(isotherm_locator)
        else:
            locator_isotherm = isotherm_locator

        if dry_adiabat_locator and not isinstance(dry_adiabat_locator, Locator):
            if not isinstance(dry_adiabat_locator, numbers.Number):
                raise ValueError('Invalid dry adiabat locator')
            locator_theta = Locator(dry_adiabat_locator)
        else:
            locator_theta = dry_adiabat_locator

        # Define the tephigram coordinate-system transformation.
        self.tephi_transform = transforms.TephiTransform()
        grid_helper1 = GridHelperCurveLinear(self.tephi_transform,
                                             tick_formatter1=_FormatterIsotherm(),
                                             grid_locator1=locator_isotherm,
                                             tick_formatter2=_FormatterTheta(),
                                             grid_locator2=locator_theta)
        self.axes = Subplot(self.figure, 1, 1, 1, grid_helper=grid_helper1)
        self.transform = self.tephi_transform + self.axes.transData
        self.axes.axis['isotherm'] = self.axes.new_floating_axis(1, 0)
        self.axes.axis['theta'] = self.axes.new_floating_axis(0, 0)
        self.axes.axis['left'].get_helper().nth_coord_ticks = 0
        self.axes.axis['left'].toggle(all=True)
        self.axes.axis['bottom'].get_helper().nth_coord_ticks = 1
        self.axes.axis['bottom'].toggle(all=True)
        self.axes.axis['top'].get_helper().nth_coord_ticks = 0
        self.axes.axis['top'].toggle(all=False)
        self.axes.axis['right'].get_helper().nth_coord_ticks = 1
        self.axes.axis['right'].toggle(all=True)
        self.axes.gridlines.set_linestyle('solid')

        self.figure.add_subplot(self.axes)

        # Configure default axes.
        axis = self.axes.axis['left']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('baseline')
        axis.major_ticklabels.set_rotation(135)
        axis = self.axes.axis['right']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('baseline')
        axis.major_ticklabels.set_rotation(-135)
        self.axes.axis['top'].major_ticklabels.set_fontsize(10)
        axis = self.axes.axis['bottom']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_ha('left')
        axis.major_ticklabels.set_va('top')
        axis.major_ticklabels.set_rotation(-45)

        # Isotherms: lines of constant temperature (degC).
        axis = self.axes.axis['isotherm']
        axis.set_axis_direction('right')
        axis.set_axislabel_direction('-')
        axis.major_ticklabels.set_rotation(90)
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('bottom')
        axis.major_ticklabels.set_color('grey')
        axis.major_ticklabels.set_visible(False)  # turned-off

        # Dry adiabats: lines of constant potential temperature (degC).
        axis = self.axes.axis['theta']
        axis.set_axis_direction('right')
        axis.set_axislabel_direction('+')
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('bottom')
        axis.major_ticklabels.set_color('grey')
        axis.major_ticklabels.set_visible(False)  # turned-off
        axis.line.set_linewidth(3)
        axis.line.set_linestyle('--')

        # Lock down the aspect ratio.
        self.axes.set_aspect(1.)
        self.axes.grid(True)

        # Initialise the text formatter for the navigation status bar.
        self.axes.format_coord = self._status_bar

        # Factor in the tephigram transform.
        ISOBAR_TEXT['transform'] = self.transform
        WET_ADIABAT_TEXT['transform'] = self.transform
        MIXING_RATIO_TEXT['transform'] = self.transform

        # Create plot collections for the tephigram isopleths.
        func = partial(isopleths.isobar, MIN_THETA, MAX_THETA, self.axes, self.transform, ISOBAR_LINE)
        self._isobars = _PlotCollection(self.axes, ISOBAR_SPEC, MAX_PRESSURE, func, ISOBAR_TEXT,
                                        fixed=ISOBAR_FIXED, minimum=MIN_PRESSURE)

        func = partial(isopleths.wet_adiabat, MAX_PRESSURE, MIN_TEMPERATURE, self.axes, self.transform, WET_ADIABAT_LINE)
        self._wet_adiabats = _PlotCollection(self.axes, WET_ADIABAT_SPEC, MAX_WET_ADIABAT, func, WET_ADIABAT_TEXT,
                                             fixed=WET_ADIABAT_FIXED, minimum=MIN_WET_ADIABAT, xfocus=True)

        func = partial(isopleths.mixing_ratio, MIN_PRESSURE, MAX_PRESSURE, self.axes, self.transform, MIXING_RATIO_LINE)
        self._mixing_ratios = _PlotCollection(self.axes, MIXING_RATIO_SPEC, MIXING_RATIOS, func, MIXING_RATIO_TEXT,
                                              fixed=MIXING_RATIO_FIXED)

        # Initialise for the tephigram plot event handler.
        plt.connect('motion_notify_event', _handler)
        self.axes.tephigram = True
        self.axes.tephigram_original_delta_xlim = self.original_delta_xlim = DEFAULT_WIDTH
        self.axes.tephigram_transform = self.tephi_transform
        self.axes.tephigram_inverse = self.tephi_transform.inverted()
        self.axes.tephigram_isopleths = [self._isobars, self._wet_adiabats, self._mixing_ratios]

       # The tephigram profiles.
        self._profiles = []
        self.axes.tephigram_profiles = self._profiles

        # Center the plot around the anchor extent.
        self._anchor = anchor
        if self._anchor is not None:
            self._anchor = np.asarray(anchor)
            if self._anchor.ndim != 2 or self._anchor.shape[-1] != 2 or \
              len(self._anchor) != 2:
                msg = 'Invalid anchor, expecting [(bottom-left-pressure, ' \
                'bottom-left-temperature), (top-right-pressure, ' \
                'top-right-temperature)]'
                raise ValueError(msg)
            (bottom_pressure, bottom_temp), \
              (top_pressure, top_temp) = self._anchor

            if (bottom_pressure - top_pressure) < 0:
                raise ValueError('Invalid anchor pressure range')
            if (bottom_temp - top_temp) < 0:
                raise ValueError('Invalid anchor temperature range')

            self._anchor = isopleths.Profile(anchor, self.axes)
            self._anchor.plot(visible=False)
            xlim, ylim = self._calculate_extents()
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)
Exemple #24
0
x_T_levels = [x_from_Tp(Ti, p_all) for Ti in T_levels]
x_thetas = [x_from_Tp(Bolton.theta_dry(theta_i, p_all),p_all) for theta_i in theta_levels]
x_mixing_ratios = [x_from_Tp((Bolton.mixing_ratio_line(p_all,MRi)+C_to_K),p_all) for MRi in mixing_ratios]
mesh_T, mesh_p = np.meshgrid(
	np.arange(-60.0, T_levels.max()-C_to_K+0.1, 0.1), p_all)
theta_ep_mesh = Bolton.theta_ep_field(mesh_T, mesh_p)



# Plotting Code!

skew_grid_helper = GridHelperCurveLinear((from_thermo, to_thermo))


fig = plt.figure()
ax = Subplot(fig, 1, 1, 1, grid_helper=skew_grid_helper)
fig.add_subplot(ax)

for yi in y_p_levels: 
	ax.plot((x_min, x_max), (yi,yi), color = (1.0, 0.8, 0.8))

for x_T in x_T_levels: 
	ax.plot(x_T, y_all_p, color=(1.0, 0.5, 0.5))

for x_theta in x_thetas:
	ax.plot(x_theta, y_all_p, color=(1.0, 0.7, 0.7))

for x_mixing_ratio in x_mixing_ratios:
	good = p_all >= 600  # restrict mixing ratio lines to below 600 mb
	ax.plot(x_mixing_ratio[good], y_all_p[good], color = (0.8, 0.8, 0.6))
Exemple #25
0
class Tephigram:
    """
    Generate a tephigram of one or more pressure and temperature data sets.

    """
    def __init__(
        self,
        figure=None,
        isotherm_locator=None,
        dry_adiabat_locator=None,
        anchor=None,
    ):
        """
        Initialise the tephigram transformation and plot axes.

        Kwargs:

        * figure:
            An existing :class:`matplotlib.figure.Figure` instance for the
            tephigram plot. If a figure is not provided, a new figure will
            be created by default.
        * isotherm_locator:
            A :class:`tephi.Locator` instance or a numeric step size
            for the isotherm lines.
        * dry_adiabat_locator:
            A :class:`tephi.Locator` instance or a numeric step size
            for the dry adiabat lines.
        * anchor:
            A sequence of two pressure, temperature pairs specifying the extent
            of the tephigram plot in terms of the bottom left hand corner and
            the top right hand corner. Pressure data points must be in units of
            mb or hPa, and temperature data points must be in units of degC.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from numpy import column_stack
            import os.path
            import tephi
            from tephi import Tephigram

            dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt')
            dry_bulb = os.path.join(tephi.DATA_DIR, 'temps.txt')
            dew_data, temp_data = tephi.loadtxt(dew_point, dry_bulb)
            dews = column_stack((dew_data.pressure, dew_data.temperature))
            temps = column_stack((temp_data.pressure, temp_data.temperature))
            tpg = Tephigram()
            tpg.plot(dews, label='Dew-point', color='blue', linewidth=2)
            tpg.plot(temps, label='Dry-bulb', color='red', linewidth=2)
            plt.show()

        """
        if not figure:
            # Create a default figure.
            self.figure = plt.figure(0, figsize=(9, 9))
        else:
            self.figure = figure

        # Configure the locators.
        if isotherm_locator and not isinstance(isotherm_locator, Locator):
            if not isinstance(isotherm_locator, numbers.Number):
                raise ValueError("Invalid isotherm locator")
            locator_isotherm = Locator(isotherm_locator)
        else:
            locator_isotherm = isotherm_locator

        if dry_adiabat_locator and not isinstance(dry_adiabat_locator,
                                                  Locator):
            if not isinstance(dry_adiabat_locator, numbers.Number):
                raise ValueError("Invalid dry adiabat locator")
            locator_theta = Locator(dry_adiabat_locator)
        else:
            locator_theta = dry_adiabat_locator

        # Define the tephigram coordinate-system transformation.
        self.tephi_transform = transforms.TephiTransform()
        ghelper = GridHelperCurveLinear(
            self.tephi_transform,
            tick_formatter1=_FormatterIsotherm(),
            grid_locator1=locator_isotherm,
            tick_formatter2=_FormatterTheta(),
            grid_locator2=locator_theta,
        )
        self.axes = Subplot(self.figure, 1, 1, 1, grid_helper=ghelper)
        self.transform = self.tephi_transform + self.axes.transData
        self.axes.axis["isotherm"] = self.axes.new_floating_axis(1, 0)
        self.axes.axis["theta"] = self.axes.new_floating_axis(0, 0)
        self.axes.axis["left"].get_helper().nth_coord_ticks = 0
        self.axes.axis["left"].toggle(all=True)
        self.axes.axis["bottom"].get_helper().nth_coord_ticks = 1
        self.axes.axis["bottom"].toggle(all=True)
        self.axes.axis["top"].get_helper().nth_coord_ticks = 0
        self.axes.axis["top"].toggle(all=False)
        self.axes.axis["right"].get_helper().nth_coord_ticks = 1
        self.axes.axis["right"].toggle(all=True)
        self.axes.gridlines.set_linestyle("solid")

        self.figure.add_subplot(self.axes)

        # Configure default axes.
        axis = self.axes.axis["left"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("baseline")
        axis.major_ticklabels.set_rotation(135)
        axis = self.axes.axis["right"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("baseline")
        axis.major_ticklabels.set_rotation(-135)
        self.axes.axis["top"].major_ticklabels.set_fontsize(10)
        axis = self.axes.axis["bottom"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_ha("left")
        axis.major_ticklabels.set_va("top")
        axis.major_ticklabels.set_rotation(-45)

        # Isotherms: lines of constant temperature (degC).
        axis = self.axes.axis["isotherm"]
        axis.set_axis_direction("right")
        axis.set_axislabel_direction("-")
        axis.major_ticklabels.set_rotation(90)
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("bottom")
        axis.major_ticklabels.set_color("grey")
        axis.major_ticklabels.set_visible(False)  # turned-off

        # Dry adiabats: lines of constant potential temperature (degC).
        axis = self.axes.axis["theta"]
        axis.set_axis_direction("right")
        axis.set_axislabel_direction("+")
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("bottom")
        axis.major_ticklabels.set_color("grey")
        axis.major_ticklabels.set_visible(False)  # turned-off
        axis.line.set_linewidth(3)
        axis.line.set_linestyle("--")

        # Lock down the aspect ratio.
        self.axes.set_aspect(1.0)
        self.axes.grid(True)

        # Initialise the text formatter for the navigation status bar.
        self.axes.format_coord = self._status_bar

        # Factor in the tephigram transform.
        ISOBAR_TEXT["transform"] = self.transform
        WET_ADIABAT_TEXT["transform"] = self.transform
        MIXING_RATIO_TEXT["transform"] = self.transform

        # Create plot collections for the tephigram isopleths.
        func = partial(
            isopleths.isobar,
            MIN_THETA,
            MAX_THETA,
            self.axes,
            self.transform,
            ISOBAR_LINE,
        )
        self._isobars = _PlotCollection(
            self.axes,
            ISOBAR_SPEC,
            MAX_PRESSURE,
            func,
            ISOBAR_TEXT,
            fixed=ISOBAR_FIXED,
            minimum=MIN_PRESSURE,
        )

        func = partial(
            isopleths.wet_adiabat,
            MAX_PRESSURE,
            MIN_TEMPERATURE,
            self.axes,
            self.transform,
            WET_ADIABAT_LINE,
        )
        self._wet_adiabats = _PlotCollection(
            self.axes,
            WET_ADIABAT_SPEC,
            MAX_WET_ADIABAT,
            func,
            WET_ADIABAT_TEXT,
            fixed=WET_ADIABAT_FIXED,
            minimum=MIN_WET_ADIABAT,
            xfocus=True,
        )

        func = partial(
            isopleths.mixing_ratio,
            MIN_PRESSURE,
            MAX_PRESSURE,
            self.axes,
            self.transform,
            MIXING_RATIO_LINE,
        )
        self._mixing_ratios = _PlotCollection(
            self.axes,
            MIXING_RATIO_SPEC,
            MIXING_RATIOS,
            func,
            MIXING_RATIO_TEXT,
            fixed=MIXING_RATIO_FIXED,
        )

        # Initialise for the tephigram plot event handler.
        plt.connect("motion_notify_event", _handler)
        self.axes.tephigram = True
        self.axes.tephigram_original_delta_xlim = DEFAULT_WIDTH
        self.original_delta_xlim = DEFAULT_WIDTH
        self.axes.tephigram_transform = self.tephi_transform
        self.axes.tephigram_inverse = self.tephi_transform.inverted()
        self.axes.tephigram_isopleths = [
            self._isobars,
            self._wet_adiabats,
            self._mixing_ratios,
        ]

        # The tephigram profiles.
        self._profiles = []
        self.axes.tephigram_profiles = self._profiles

        # Center the plot around the anchor extent.
        self._anchor = anchor
        if self._anchor is not None:
            self._anchor = np.asarray(anchor)
            if (self._anchor.ndim != 2 or self._anchor.shape[-1] != 2
                    or len(self._anchor) != 2):
                msg = ("Invalid anchor, expecting [(bottom-left-pressure, "
                       "bottom-left-temperature), (top-right-pressure, "
                       "top-right-temperature)]")
                raise ValueError(msg)
            (
                (bottom_pressure, bottom_temp),
                (top_pressure, top_temp),
            ) = self._anchor

            if (bottom_pressure - top_pressure) < 0:
                raise ValueError("Invalid anchor pressure range")
            if (bottom_temp - top_temp) < 0:
                raise ValueError("Invalid anchor temperature range")

            self._anchor = isopleths.Profile(anchor, self.axes)
            self._anchor.plot(visible=False)
            xlim, ylim = self._calculate_extents()
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

    def plot(self, data, **kwargs):
        """
        Plot the environmental lapse rate profile of the pressure and
        temperature data points.

        The pressure and temperature data points are transformed into
        potential temperature and temperature data points before plotting.

        By default, the tephigram will automatically center the plot around
        all profiles.

        .. warning::
            Pressure data points must be in units of mb or hPa, and temperature
            data points must be in units of degC.

        Args:

        * data: pressure and temperature pair data points.

        .. note::
            All keyword arguments are passed through to
            :func:`matplotlib.pyplot.plot`.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from tephi import Tephigram

            tpg = Tephigram()
            data = [[1006, 26.4], [924, 20.3], [900, 19.8],
                    [850, 14.5], [800, 12.9], [755, 8.3]]
            profile = tpg.plot(data, color='red', linestyle='--',
                               linewidth=2, marker='o')
            barbs = [(10, 45, 900), (20, 60, 850), (25, 90, 800)]
            profile.barbs(barbs)
            plt.show()

        For associating wind barbs with an environmental lapse rate profile,
        see :meth:`~tephi.isopleths.Profile.barbs`.

        """
        profile = isopleths.Profile(data, self.axes)
        profile.plot(**kwargs)
        self._profiles.append(profile)

        # Center the tephigram plot around all the profiles.
        if self._anchor is None:
            xlim, ylim = self._calculate_extents(xfactor=0.25, yfactor=0.05)
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

        # Refresh the tephigram plot isopleths.
        _refresh_isopleths(self.axes)

        # Show the plot legend.
        if "label" in kwargs:
            font_properties = FontProperties(size="x-small")
            plt.legend(
                loc="upper left",
                fancybox=True,
                shadow=True,
                prop=font_properties,
            )

        return profile

    def _status_bar(self, x_point, y_point):
        """Generate text for the interactive backend navigation status bar."""

        temperature, theta = transforms.convert_xy2Tt(x_point, y_point)
        pressure, _ = transforms.convert_Tt2pT(temperature, theta)
        xlim = self.axes.get_xlim()
        zoom = (xlim[1] - xlim[0]) / self.original_delta_xlim
        msg = "T:{:.2f}, theta:{:.2f}, phi:{:.2f} (zoom:{:.3f})"
        text = msg.format(float(temperature), float(theta), float(pressure),
                          zoom)

        return text

    def _calculate_extents(self, xfactor=None, yfactor=None):
        min_x = min_y = 1e10
        max_x = max_y = -1e-10
        profiles = self._profiles
        transform = self.tephi_transform.transform

        if self._anchor is not None:
            profiles = [self._anchor]

        for profile in profiles:
            temperature = profile.temperature.reshape(-1, 1)
            theta = profile.theta.reshape(-1, 1)
            xy_points = transform(np.concatenate((temperature, theta), axis=1))
            x_points = xy_points[:, 0]
            y_points = xy_points[:, 1]
            min_x = np.min([min_x, np.min(x_points)])
            min_y = np.min([min_y, np.min(y_points)])
            max_x = np.max([max_x, np.max(x_points)])
            max_y = np.max([max_y, np.max(y_points)])

        if xfactor is not None:
            delta_x = max_x - min_x
            min_x, max_x = min_x - xfactor * delta_x, max_x + xfactor * delta_x

        if yfactor is not None:
            delta_y = max_y - min_y
            min_y, max_y = min_y - yfactor * delta_y, max_y + yfactor * delta_y

        return ([min_x, max_x], [min_y, max_y])
Exemple #26
0
class MainPlotController(object):
    """
        A controller for the main plot canvas.
        Sets up the widgets and has image exporting functionality.
    """
    
    file_filters = ("Portable Network Graphics (PNG)", "*.png"), \
                   ("Scalable Vector Graphics (SVG)", "*.svg"), \
                   ("Portable Document Format (PDF)", "*.pdf")

    _canvas = None
    @property
    def canvas(self):
        if not self._canvas:
            self.setup_figure()
            self.setup_canvas()
            self.setup_content()
        return self._canvas

    # ------------------------------------------------------------
    #      View integration getters
    # ------------------------------------------------------------
    def get_toolbar_widget(self, window):
        return NavigationToolbar(self.canvas, window)

    def get_canvas_widget(self):
        return self.canvas
    
    # ------------------------------------------------------------
    #      Initialization and other internals
    # ------------------------------------------------------------
    def __init__(self, status_callback, marker_callback, *args, **kwargs):
        self.setup_layout_cache()
        self.setup_figure()
        self.setup_canvas()
        self.setup_content(status_callback, marker_callback)

    def setup_layout_cache(self):
        self.position_setup = PositionSetup()
        self.labels = list()
        self.marker_lbls = list()
        self._proxies = dict()
        self.scale = 1.0
        self.stats = False
        self._last_pos = None

    def setup_figure(self):
        self.figure = Figure(dpi=72, facecolor="#FFFFFF", linewidth=0)
        self.figure.subplots_adjust(hspace=0.0, wspace=0.0)

    def setup_canvas(self):
        self._canvas = FigureCanvasGTK(self.figure)

    def setup_content(self, status_callback, marker_callback):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, facecolor=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.mtc = MotionTracker(self, status_callback)
        self.cc = ClickCatcher(self, marker_callback)

        #self.update()

    # ------------------------------------------------------------
    #      Update methods
    # ------------------------------------------------------------
    def draw(self):
        self._last_pos = self.fix_before_drawing()
        self.figure.canvas.draw()

    def fix_after_drawing(self, *args):
        _new_pos = self.fix_before_drawing()
        
        if _new_pos != self._last_pos:
            self.figure.canvas.draw()
        self._last_pos = _new_pos

        return False

    def fix_before_drawing(self, *args):
        """
            Fixes alignment issues due to longer labels or smaller windows
            Is executed after an initial draw event, since we can then retrieve
            the actual label dimensions and shift/resize the plot accordingly.
        """
        renderer = get_renderer(self.figure)        
        if not renderer or not self._canvas.get_realized():
            return False
        
        # Fix left side for wide specimen labels:
        if len(self.labels) > 0:
            bbox = self._get_joint_bbox(self.labels, renderer)
            if bbox is not None: 
                self.position_setup.left = self.position_setup.default_left + bbox.width
        # Fix top for high marker labels:
        if len(self.marker_lbls) > 0:
            bbox = self._get_joint_bbox([ label for label, flag, _ in self.marker_lbls if flag ], renderer)
            if bbox is not None: 
                self.position_setup.top = self.position_setup.default_top - bbox.height
        # Fix bottom for x-axis label:
        bottom_label = self.plot.axis["bottom"].label
        if bottom_label is not None:
            bbox = self._get_joint_bbox([bottom_label], renderer)
            if bbox is not None:
                self.position_setup.bottom = self.position_setup.default_bottom + (bbox.ymax - bbox.ymin) * 2.0 # somehow we need this?

        # Calculate new plot position & set it:
        plot_pos = self.position_setup.position
        self.plot.set_position(plot_pos)

        # Adjust specimen label position
        for label in self.labels:
            label.set_x(plot_pos[0] - 0.025)

        # Adjust marker label position
        for label, flag, y_offset in self.marker_lbls:
            if flag:
                newy = plot_pos[1] + plot_pos[3] + y_offset - 0.025
                label.set_y(newy)
        
        _new_pos = self.position_setup.to_string()
        return _new_pos
    
    def update(self, clear=False, project=None, specimens=None):
        """
            Updates the entire plot with the given information.
        """
        if clear: self.plot.cla()

        if project and specimens:
            self.labels, self.marker_lbls = plot_specimens(
                self.plot, self.position_setup, self.cc,
                project, specimens
            )
            # get mixtures for the selected specimens:
            plot_mixtures(self.plot, project, [ mixture for mixture in project.mixtures if any(specimen in mixture.specimens for specimen in specimens) ])

        update_axes(
            self.plot, self.position_setup,
            project, specimens
        )

        self.draw()

    # ------------------------------------------------------------
    #      Plot position and size calculations
    # ------------------------------------------------------------
    def _get_joint_bbox(self, container, renderer):
        bboxes = []
        try:
            for text in container:
                bbox = text.get_window_extent(renderer=renderer)
                # the figure transform goes from relative coords->pixels and we
                # want the inverse of that
                bboxi = bbox.inverse_transformed(self.figure.transFigure)
                bboxes.append(bboxi)
        except (RuntimeError, ValueError):
            logger.exception("Caught unhandled exception when joining boundig boxes")
            return None # don't continue
        # this is the bbox that bounds all the bboxes, again in relative
        # figure coords
        if len(bboxes) > 0:
            bbox = transforms.Bbox.union(bboxes)
            return bbox
        else:
            return None

    # ------------------------------------------------------------
    #      Graph exporting
    # ------------------------------------------------------------
    def save(self, parent=None, current_name="graph", size="auto", num_specimens=1, offset=0.75):
        """
            Displays a save dialog to export an image from the current plot.
        """
        # Parse arguments:
        width, height = 0, 0
        if size == "auto":
            descr, width, height, dpi = settings.OUTPUT_PRESETS[0]
        else:
            width, height, dpi = list(map(float, size.replace("@", "x").split("x")))

        # Load gui:
        builder = Gtk.Builder()
        builder.add_from_file(resource_filename("pyxrd.specimen", "glade/save_graph_size.glade")) # FIXME move this to this namespace!!
        size_expander = builder.get_object("size_expander")
        cmb_presets = builder.get_object("cmb_presets")

        # Setup combo with presets:
        cmb_store = Gtk.ListStore(str, int, int, float)
        for row in settings.OUTPUT_PRESETS:
            cmb_store.append(row)
        cmb_presets.clear()
        cmb_presets.set_model(cmb_store)
        cell = Gtk.CellRendererText()
        cmb_presets.pack_start(cell, True)
        cmb_presets.add_attribute(cell, 'text', 0)
        def on_cmb_changed(cmb, *args):
            itr = cmb.get_active_iter()
            w, h, d = cmb_store.get(itr, 1, 2, 3)
            entry_w.set_text(str(w))
            entry_h.set_text(str(h))
            entry_dpi.set_text(str(d))
        cmb_presets.connect('changed', on_cmb_changed)

        # Setup input boxes:
        entry_w = builder.get_object("entry_width")
        entry_h = builder.get_object("entry_height")
        entry_dpi = builder.get_object("entry_dpi")
        entry_w.set_text(str(width))
        entry_h.set_text(str(height))
        entry_dpi.set_text(str(dpi))

        # What to do when the user wants to save this:
        def on_accept(dialog):
            # Get the width, height & dpi
            width = float(entry_w.get_text())
            height = float(entry_h.get_text())
            dpi = float(entry_dpi.get_text())
            i_width, i_height = width / dpi, height / dpi
            # Save it all right!
            self.save_figure(dialog.filename, dpi, i_width, i_height)

        # Ask the user where, how and if he wants to save:
        DialogFactory.get_save_dialog(
            "Save Graph", parent=parent,
            filters=self.file_filters, current_name=current_name,
            extra_widget=size_expander
        ).run(on_accept)

    def save_figure(self, filename, dpi, i_width, i_height):
        """
            Save the current plot
            
            Arguments:
             filename: the filename to save to (either .png, .pdf or .svg)
             dpi: Dots-Per-Inch resolution
             i_width: the width in inch
             i_height: the height in inch
        """
        # Get original settings:
        original_dpi = self.figure.get_dpi()
        original_width, original_height = self.figure.get_size_inches()
        # Set everything according to the user selection:
        self.figure.set_dpi(dpi)
        self.figure.set_size_inches((i_width, i_height))
        self.figure.canvas.draw() # replot
        bbox_inches = matplotlib.transforms.Bbox.from_bounds(0, 0, i_width, i_height)
        # Save the figure:
        self.figure.savefig(filename, dpi=dpi, bbox_inches=bbox_inches)
        # Put everything back the way it was:
        self.figure.set_dpi(original_dpi)
        self.figure.set_size_inches((original_width, original_height))
        self.figure.canvas.draw() # replot

    pass # end of class
                     s=4,
                     marker='s',
                     vmin=vmin,
                     vmax=vmax,
                     latlon=True,
                     rasterized=True)
        smap.draw_inset_colorbar(label=r'mag arcsec$^{-2}$')

        ax1 = plt.gca()
        #ax1.annotate(f"{band}-band",(0.05,0.9),xycoords='axes fraction',
        #             fontsize=14)
        ax1.axis['right'].major_ticklabels.set_visible(False)
        #ax1.axis['top'].major_ticklabels.set_visible(False)

        # Plot histogram
        ax2 = Subplot(fig, gridspec[2])
        fig.add_subplot(ax2)
        plt.sca(ax2)
        #fig.add_subplot(gridspec[2])

        bins = np.linspace(x['sb'].min(), x['sb'].max(), 35)
        ret = draw_hist(hpxmap,
                        label=band,
                        color=v,
                        peak=False,
                        bins=bins,
                        density=True)
        ax2.yaxis.set_major_locator(MaxNLocator(6, prune='both'))
        ax2.axis['left'].major_ticklabels.set_visible(True)
        ax2.axis['right'].major_ticklabels.set_visible(False)
        ax2.axis['left'].label.set_visible(True)
Exemple #28
0
def curvelinear_test1(fig):
    """
    grid for custom transform.
    """
    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y-x
    def inv_tr(x,y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y+x
    grid_helper = GridHelperCurveLinear((tr, inv_tr))
    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    fig.add_subplot(ax1)
    xx, yy = tr([3, 6], [5.0, 10.])
    ax1.plot(xx, yy)
    ax1.set_aspect(1.)
    ax1.set_xlim(0, 10.)
    ax1.set_ylim(0, 10.)
    ax1.axis["t"]=ax1.new_floating_axis(0, 3.)
    ax1.axis["t2"]=ax1.new_floating_axis(1, 7.)
    ax1.grid(True)
Exemple #29
0
class DGSPlannerGUI(QtGui.QWidget):
    def __init__(self,ol=None,parent=None):
        # pylint: disable=unused-argument,super-on-old-class
        super(DGSPlannerGUI,self).__init__(parent)
        #OrientedLattice
        if ValidateOL(ol):
            self.ol=ol
        else:
            self.ol=mantid.geometry.OrientedLattice()
        self.masterDict=dict() #holds info about instrument and ranges
        self.updatedInstrument=False
        self.updatedOL=False
        self.wg=None #workspace group
        self.instrumentWidget=InstrumentSetupWidget.InstrumentSetupWidget(self)
        self.setLayout(QtGui.QHBoxLayout())
        controlLayout=QtGui.QVBoxLayout()
        controlLayout.addWidget(self.instrumentWidget)
        self.ublayout=QtGui.QHBoxLayout()
        self.classic=ClassicUBInputWidget.ClassicUBInputWidget(self.ol)
        self.ublayout.addWidget(self.classic,alignment=QtCore.Qt.AlignTop,stretch=1)
        self.matrix=MatrixUBInputWidget.MatrixUBInputWidget(self.ol)
        self.ublayout.addWidget(self.matrix,alignment=QtCore.Qt.AlignTop,stretch=1)
        controlLayout.addLayout(self.ublayout)
        self.dimensionWidget=DimensionSelectorWidget.DimensionSelectorWidget(self)
        controlLayout.addWidget(self.dimensionWidget)
        plotControlLayout=QtGui.QGridLayout()
        self.plotButton=QtGui.QPushButton("Plot",self)
        self.oplotButton=QtGui.QPushButton("Overplot",self)
        self.helpButton=QtGui.QPushButton("?",self)
        self.colorLabel=QtGui.QLabel('Color by angle',self)
        self.colorButton=QtGui.QCheckBox(self)
        self.colorButton.toggle()
        self.aspectLabel=QtGui.QLabel('Aspect ratio 1:1',self)
        self.aspectButton=QtGui.QCheckBox(self)
        self.saveButton=QtGui.QPushButton("Save Figure",self)
        plotControlLayout.addWidget(self.plotButton,0,0)
        plotControlLayout.addWidget(self.oplotButton,0,1)
        plotControlLayout.addWidget(self.colorLabel,0,2,QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.colorButton,0,3)
        plotControlLayout.addWidget(self.aspectLabel,0,4,QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.aspectButton,0,5)
        plotControlLayout.addWidget(self.helpButton,0,6)
        plotControlLayout.addWidget(self.saveButton,0,7)
        controlLayout.addLayout(plotControlLayout)
        self.layout().addLayout(controlLayout)

        #figure
        self.figure=Figure()
        self.figure.patch.set_facecolor('white')
        self.canvas=FigureCanvas(self.figure)
        self.grid_helper = GridHelperCurveLinear((self.tr, self.inv_tr))
        self.trajfig = Subplot(self.figure, 1, 1, 1, grid_helper=self.grid_helper)
        self.trajfig.hold(True)
        self.figure.add_subplot(self.trajfig)
        self.layout().addWidget(self.canvas)
        self.needToClear=False
        self.saveDir=''

        #connections
        self.matrix.UBmodel.changed.connect(self.updateUB)
        self.matrix.UBmodel.changed.connect(self.classic.updateOL)
        self.classic.changed.connect(self.matrix.UBmodel.updateOL)
        self.classic.changed.connect(self.updateUB)
        self.instrumentWidget.changed.connect(self.updateParams)
        self.dimensionWidget.changed.connect(self.updateParams)
        self.plotButton.clicked.connect(self.updateFigure)
        self.oplotButton.clicked.connect(self.updateFigure)
        self.helpButton.clicked.connect(self.help)
        self.saveButton.clicked.connect(self.save)
        #force an update of values
        self.instrumentWidget.updateAll()
        self.dimensionWidget.updateChanges()
        #help
        self.assistantProcess = QtCore.QProcess(self)
        # pylint: disable=protected-access
        self.collectionFile=os.path.join(mantid._bindir,'../docs/qthelp/MantidProject.qhc')
        version = ".".join(mantid.__version__.split(".")[:2])
        self.qtUrl='qthelp://org.sphinx.mantidproject.'+version+'/doc/interfaces/DGSPlanner.html'
        self.externalUrl='http://docs.mantidproject.org/nightly/interfaces/DGSPlanner.html'
        #control for cancel button
        self.iterations=0
        self.progress_canceled=False

        #register startup
        mantid.UsageService.registerFeatureUsage("Interface","DGSPlanner",False)

    @QtCore.pyqtSlot(mantid.geometry.OrientedLattice)
    def updateUB(self,ol):
        self.ol=ol
        self.updatedOL=True
        self.trajfig.clear()

    @QtCore.pyqtSlot(dict)
    def updateParams(self,d):
        if self.sender() is self.instrumentWidget:
            self.updatedInstrument=True
        if 'dimBasis' in d and 'dimBasis' in self.masterDict and d['dimBasis']!=self.masterDict['dimBasis']:
            self.needToClear=True
        if 'dimIndex' in d and 'dimIndex' in self.masterDict and d['dimIndex']!=self.masterDict['dimIndex']:
            self.needToClear=True
        self.masterDict.update(copy.deepcopy(d))

    def help(self):
        try:
            import pymantidplot
            pymantidplot.proxies.showCustomInterfaceHelp('DGSPlanner')
        except ImportError:
            self.assistantProcess.close()
            self.assistantProcess.waitForFinished()
            helpapp = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.BinariesPath) + QtCore.QDir.separator()
            helpapp += 'assistant'
            args = ['-enableRemoteControl', '-collectionFile',self.collectionFile,'-showUrl',self.qtUrl]
            if os.path.isfile(helpapp) and os.path.isfile(self.collectionFile):
                self.assistantProcess.close()
                self.assistantProcess.waitForFinished()
                self.assistantProcess.start(helpapp, args)
            else:
                mqt.MantidQt.API.MantidDesktopServices.openUrl(QtCore.QUrl(self.externalUrl))

    def closeEvent(self,event):
        self.assistantProcess.close()
        self.assistantProcess.waitForFinished()
        event.accept()

    # pylint: disable=too-many-locals
    def updateFigure(self):
        # pylint: disable=too-many-branches
        if self.updatedInstrument or self.progress_canceled:
            self.progress_canceled=False
            #get goniometer settings first
            gonioAxis0values=numpy.arange(self.masterDict['gonioMinvals'][0],self.masterDict['gonioMaxvals'][0]
                                          +0.1*self.masterDict['gonioSteps'][0],self.masterDict['gonioSteps'][0])
            gonioAxis1values=numpy.arange(self.masterDict['gonioMinvals'][1],self.masterDict['gonioMaxvals'][1]
                                          +0.1*self.masterDict['gonioSteps'][1],self.masterDict['gonioSteps'][1])
            gonioAxis2values=numpy.arange(self.masterDict['gonioMinvals'][2],self.masterDict['gonioMaxvals'][2]
                                          +0.1*self.masterDict['gonioSteps'][2],self.masterDict['gonioSteps'][2])
            self.iterations=len(gonioAxis0values)*len(gonioAxis1values)*len(gonioAxis2values)
            if self.iterations>10:
                reply = QtGui.QMessageBox.warning(self, 'Goniometer',"More than 10 goniometer settings. This might be long.\n"
                                                  "Are you sure you want to proceed?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                                                  QtGui.QMessageBox.No)
                if reply==QtGui.QMessageBox.No:
                    return
            if self.wg is not None:
                mantid.simpleapi.DeleteWorkspace(self.wg)
            mantid.simpleapi.LoadEmptyInstrument(mantid.api.ExperimentInfo.getInstrumentFilename(self.masterDict['instrument']),
                                                 OutputWorkspace="__temp_instrument")
            if self.masterDict['instrument']=='HYSPEC':
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",LogName='msd',LogText='1798.5',LogType='Number Series')
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",LogName='s2',
                                              LogText=str(self.masterDict['S2']),LogType='Number Series')
                mantid.simpleapi.LoadInstrument(Workspace="__temp_instrument", RewriteSpectraMap=True, InstrumentName="HYSPEC")
            #masking
            if 'maskFilename' in self.masterDict and len(self.masterDict['maskFilename'].strip())>0:
                try:
                    __maskWS=mantid.simpleapi.Load(self.masterDict['maskFilename'])
                    mantid.simpleapi.MaskDetectors(Workspace="__temp_instrument",MaskedWorkspace=__maskWS)
                except (ValueError,RuntimeError) as e:
                    reply = QtGui.QMessageBox.critical(self, 'Error',"The following error has occured in loading the mask:\n"+
                                                       str(e)+"\nDo you want to continue without mask?",
                                                       QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
                    if reply==QtGui.QMessageBox.No:
                        return
            if self.masterDict['makeFast']:
                sp=range(mantid.mtd["__temp_instrument"].getNumberHistograms())
                tomask=sp[::4]+sp[1::4]+sp[2::4]
                mantid.simpleapi.MaskDetectors("__temp_instrument",SpectraList=tomask)
            i=0
            groupingStrings=[]
            progressDialog = QtGui.QProgressDialog(self)
            progressDialog.setMinimumDuration(0)
            progressDialog.setCancelButtonText("&Cancel")
            progressDialog.setRange(0, self.iterations)
            progressDialog.setWindowTitle("DGSPlanner progress")
            for g0 in gonioAxis0values:
                for g1 in gonioAxis1values:
                    for g2 in gonioAxis2values:
                        name="__temp_instrument"+str(i)
                        i+=1
                        progressDialog.setValue(i)
                        progressDialog.setLabelText("Creating workspace %d of %d..." % (i, self.iterations))
                        QtGui.qApp.processEvents()
                        if progressDialog.wasCanceled():
                            self.progress_canceled=True
                            progressDialog.close()
                            return
                        groupingStrings.append(name)
                        mantid.simpleapi.CloneWorkspace("__temp_instrument",OutputWorkspace=name)
                        mantid.simpleapi.SetGoniometer(Workspace=name,
                                                       Axis0=str(g0)+","+self.masterDict['gonioDirs'][0]+
                                                       ","+str(self.masterDict['gonioSenses'][0]),
                                                       Axis1=str(g1)+","+self.masterDict['gonioDirs'][1]+
                                                       ","+str(self.masterDict['gonioSenses'][1]),
                                                       Axis2=str(g2)+","+self.masterDict['gonioDirs'][2]+
                                                       ","+str(self.masterDict['gonioSenses'][2]))
            progressDialog.close()
            mantid.simpleapi.DeleteWorkspace("__temp_instrument")
            self.wg=mantid.simpleapi.GroupWorkspaces(groupingStrings,OutputWorkspace="__temp_instrument")
            self.updatedInstrument=False
        #set the UB
        if self.updatedOL or not self.wg[0].sample().hasOrientedLattice():
            mantid.simpleapi.SetUB(self.wg,UB=self.ol.getUB())
            self.updatedOL=False
        #calculate coverage
        dimensions=['Q1','Q2','Q3','DeltaE']
        progressDialog = QtGui.QProgressDialog(self)
        progressDialog.setMinimumDuration(0)
        progressDialog.setCancelButtonText("&Cancel")
        progressDialog.setRange(0, self.iterations)
        progressDialog.setWindowTitle("DGSPlanner progress")
        for i in range(self.iterations):
            progressDialog.setValue(i)
            progressDialog.setLabelText("Calculating orientation %d of %d..." % (i, self.iterations))
            QtGui.qApp.processEvents()
            if progressDialog.wasCanceled():
                self.progress_canceled=True
                progressDialog.close()
                return

            __mdws=mantid.simpleapi.CalculateCoverageDGS(self.wg[i],
                                                         Q1Basis=self.masterDict['dimBasis'][0],
                                                         Q2Basis=self.masterDict['dimBasis'][1],
                                                         Q3Basis=self.masterDict['dimBasis'][2],
                                                         IncidentEnergy=self.masterDict['Ei'],
                                                         Dimension1=dimensions[self.masterDict['dimIndex'][0]],
                                                         Dimension1Min=float2Input(self.masterDict['dimMin'][0]),
                                                         Dimension1Max=float2Input(self.masterDict['dimMax'][0]),
                                                         Dimension1Step=float2Input(self.masterDict['dimStep'][0]),
                                                         Dimension2=dimensions[self.masterDict['dimIndex'][1]],
                                                         Dimension2Min=float2Input(self.masterDict['dimMin'][1]),
                                                         Dimension2Max=float2Input(self.masterDict['dimMax'][1]),
                                                         Dimension2Step=float2Input(self.masterDict['dimStep'][1]),
                                                         Dimension3=dimensions[self.masterDict['dimIndex'][2]],
                                                         Dimension3Min=float2Input(self.masterDict['dimMin'][2]),
                                                         Dimension3Max=float2Input(self.masterDict['dimMax'][2]),
                                                         Dimension4=dimensions[self.masterDict['dimIndex'][3]],
                                                         Dimension4Min=float2Input(self.masterDict['dimMin'][3]),
                                                         Dimension4Max=float2Input(self.masterDict['dimMax'][3]))

            if i==0:
                intensity=__mdws.getSignalArray()[:,:,0,0]*1. #to make it writeable
            else:
                if self.colorButton.isChecked():
                    tempintensity=  __mdws.getSignalArray()[:,:,0,0]
                    intensity[numpy.where( tempintensity>0)]=i+1.
                else:
                    tempintensity=  __mdws.getSignalArray()[:,:,0,0]
                    intensity[numpy.where( tempintensity>0)]=1.
        progressDialog.close()
        x = numpy.linspace(__mdws.getDimension(0).getMinimum(), __mdws.getDimension(0).getMaximum(),intensity.shape[0] )
        y = numpy.linspace(__mdws.getDimension(1).getMinimum(), __mdws.getDimension(1).getMaximum(),intensity.shape[1] )
        Y,X = numpy.meshgrid(y,x)
        xx, yy = self.tr(X, Y)
        Z=numpy.ma.masked_array(intensity,intensity==0)
        Z = Z[:-1, :-1]
        #plotting
        if self.sender() is self.plotButton or self.needToClear:
            self.figure.clear()
            self.trajfig.clear()
            self.figure.add_subplot(self.trajfig)
            self.needToClear=False
        self.trajfig.pcolorfast(xx,yy,Z)

        if self.aspectButton.isChecked():
            self.trajfig.set_aspect(1.)
        else:
            self.trajfig.set_aspect('auto')
        self.trajfig.set_xlabel(self.masterDict['dimNames'][0])
        self.trajfig.set_ylabel(self.masterDict['dimNames'][1])
        self.trajfig.grid(True)
        self.canvas.draw()
        mantid.simpleapi.DeleteWorkspace(__mdws)

    def save(self):
        fileName = str(QtGui.QFileDialog.getSaveFileName(self, 'Save Plot', self.saveDir,'*.png'))
        data = "Instrument "+self.masterDict['instrument']+'\n'
        if self.masterDict['instrument']=='HYSPEC':
            data+= "S2 = "+str(self.masterDict['S2'])+'\n'
        data+= "Ei = "+str(self.masterDict['Ei'])+' meV\n'
        data+= "Goniometer values:\n"
        gonioAxis0values=numpy.arange(self.masterDict['gonioMinvals'][0],self.masterDict['gonioMaxvals'][0]
                                      +0.1*self.masterDict['gonioSteps'][0],self.masterDict['gonioSteps'][0])
        gonioAxis1values=numpy.arange(self.masterDict['gonioMinvals'][1],self.masterDict['gonioMaxvals'][1]
                                      +0.1*self.masterDict['gonioSteps'][1],self.masterDict['gonioSteps'][1])
        gonioAxis2values=numpy.arange(self.masterDict['gonioMinvals'][2],self.masterDict['gonioMaxvals'][2]
                                      +0.1*self.masterDict['gonioSteps'][2],self.masterDict['gonioSteps'][2])
        for g0 in gonioAxis0values:
            for g1 in gonioAxis1values:
                for g2 in gonioAxis2values:
                    data+="    "+self.masterDict['gonioLabels'][0]+" = "+str(g0)
                    data+="    "+self.masterDict['gonioLabels'][1]+" = "+str(g1)
                    data+="    "+self.masterDict['gonioLabels'][2]+" = "+str(g2)+'\n'
        data+= "Lattice parameters:\n"
        data+="    a = "+str(self.ol.a())+"    b = "+str(self.ol.b())+"    c = "+str(self.ol.c())+'\n'
        data+="    alpha = "+str(self.ol.alpha())+"    beta = "+str(self.ol.beta())+"    gamma = "+str(self.ol.gamma())+'\n'
        data+= "Orientation vectors:\n"
        data+="    u = "+str(self.ol.getuVector())+'\n'
        data+="    v = "+str(self.ol.getvVector())+'\n'
        data+="Integrated "+self.masterDict['dimNames'][2]+" between "+\
              str(self.masterDict['dimMin'][2])+" and "+str(self.masterDict['dimMax'][2])+'\n'
        data+="Integrated "+self.masterDict['dimNames'][3]+" between "+\
              str(self.masterDict['dimMin'][3])+" and "+str(self.masterDict['dimMax'][3])+'\n'

        info=self.figure.text(0.2,0,data,verticalalignment='top')
        self.figure.savefig(fileName,bbox_inches='tight',additional_artists=info)
        self.saveDir=os.path.dirname(fileName)

    def tr(self,x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        #one of the axes is energy
        if self.masterDict['dimIndex'][0]==3 or self.masterDict['dimIndex'][1]==3:
            return x,y
        else:
            h1,k1,l1=(float(temp) for temp in self.masterDict['dimBasis'][self.masterDict['dimIndex'][0]].split(','))
            h2,k2,l2=(float(temp) for temp in self.masterDict['dimBasis'][self.masterDict['dimIndex'][1]].split(','))
            angle=numpy.radians(self.ol.recAngle(h1,k1,l1,h2,k2,l2))
            return 1.*x+numpy.cos(angle)*y,  numpy.sin(angle)*y

    def inv_tr(self,x,y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        #one of the axes is energy
        if self.masterDict['dimIndex'][0]==3 or self.masterDict['dimIndex'][1]==3:
            return x,y
        else:
            h1,k1,l1=(float(temp) for temp in self.masterDict['dimBasis'][self.masterDict['dimIndex'][0]].split(','))
            h2,k2,l2=(float(temp) for temp in self.masterDict['dimBasis'][self.masterDict['dimIndex'][1]].split(','))
            angle=numpy.radians(self.ol.recAngle(h1,k1,l1,h2,k2,l2))
            return 1.*x-y/numpy.tan(angle),  y/numpy.sin(angle)
Exemple #30
0
class SliceViewerDataView(QWidget):
    """The view for the data portion of the sliceviewer"""

    def __init__(self, presenter: IDataViewSubscriber, dims_info, can_normalise, parent=None, conf=None):
        super().__init__(parent)

        self.presenter = presenter

        self.image = None
        self.line_plots_active = False
        self.can_normalise = can_normalise
        self.nonortho_transform = None
        self.conf = conf

        self._line_plots = None
        self._image_info_tracker = None
        self._region_selection_on = False
        self._orig_lims = None

        # Dimension widget
        self.dimensions_layout = QGridLayout()
        self.dimensions = DimensionWidget(dims_info, parent=self)
        self.dimensions.dimensionsChanged.connect(self.presenter.dimensions_changed)
        self.dimensions.valueChanged.connect(self.presenter.slicepoint_changed)
        self.dimensions_layout.addWidget(self.dimensions, 1, 0, 1, 1)

        self.colorbar_layout = QVBoxLayout()
        self.colorbar_layout.setContentsMargins(0, 0, 0, 0)
        self.colorbar_layout.setSpacing(0)

        self.image_info_widget = ImageInfoWidget(self)
        self.image_info_widget.setToolTip("Information about the selected pixel")
        self.track_cursor = QCheckBox("Track Cursor", self)
        self.track_cursor.setToolTip(
            "Update the image readout table when the cursor is over the plot. "
            "If unticked the table will update only when the plot is clicked")
        self.dimensions_layout.setHorizontalSpacing(10)
        self.dimensions_layout.addWidget(self.track_cursor, 0, 1, Qt.AlignRight)
        self.dimensions_layout.addWidget(self.image_info_widget, 1, 1)
        self.track_cursor.setChecked(True)
        self.track_cursor.stateChanged.connect(self.on_track_cursor_state_change)

        # normalization options
        if can_normalise:
            self.norm_label = QLabel("Normalization")
            self.colorbar_layout.addWidget(self.norm_label)
            self.norm_opts = QComboBox()
            self.norm_opts.addItems(["None", "By bin width"])
            self.norm_opts.setToolTip("Normalization options")
            self.colorbar_layout.addWidget(self.norm_opts)

        # MPL figure + colorbar
        self.fig = Figure()
        self.ax = None
        self.image = None
        self._grid_on = False
        self.fig.set_facecolor(self.palette().window().color().getRgbF())
        self.canvas = SliceViewerCanvas(self.fig)
        self.canvas.mpl_connect('button_release_event', self.mouse_release)
        self.canvas.mpl_connect('button_press_event', self.presenter.canvas_clicked)

        self.colorbar_label = QLabel("Colormap")
        self.colorbar_layout.addWidget(self.colorbar_label)
        norm_scale = self.get_default_scale_norm()
        self.colorbar = ColorbarWidget(self, norm_scale)
        self.colorbar.cmap.setToolTip("Colormap options")
        self.colorbar.crev.setToolTip("Reverse colormap")
        self.colorbar.norm.setToolTip("Colormap normalisation options")
        self.colorbar.powerscale.setToolTip("Power colormap scale")
        self.colorbar.cmax.setToolTip("Colormap maximum limit")
        self.colorbar.cmin.setToolTip("Colormap minimum limit")
        self.colorbar.autoscale.setToolTip("Automatically changes colormap limits when zooming on the plot")
        self.colorbar_layout.addWidget(self.colorbar)
        self.colorbar.colorbarChanged.connect(self.update_data_clim)
        self.colorbar.scaleNormChanged.connect(self.scale_norm_changed)
        # make width larger to fit image readout table
        self.colorbar.setMaximumWidth(200)

        # MPL toolbar
        self.toolbar_layout = QHBoxLayout()
        self.mpl_toolbar = SliceViewerNavigationToolbar(self.canvas, self, False)
        self.mpl_toolbar.gridClicked.connect(self.toggle_grid)
        self.mpl_toolbar.linePlotsClicked.connect(self.on_line_plots_toggle)
        self.mpl_toolbar.regionSelectionClicked.connect(self.on_region_selection_toggle)
        self.mpl_toolbar.homeClicked.connect(self.on_home_clicked)
        self.mpl_toolbar.nonOrthogonalClicked.connect(self.on_non_orthogonal_axes_toggle)
        self.mpl_toolbar.zoomPanClicked.connect(self.presenter.zoom_pan_clicked)
        self.mpl_toolbar.zoomPanFinished.connect(self.on_data_limits_changed)
        self.toolbar_layout.addWidget(self.mpl_toolbar)

        # Status bar
        self.status_bar = QStatusBar(parent=self)
        self.status_bar.setStyleSheet('QStatusBar::item {border: None;}')  # Hide spacers between button and label
        self.status_bar_label = QLabel()
        self.help_button = QToolButton()
        self.help_button.setText("?")
        self.status_bar.addWidget(self.help_button)
        self.status_bar.addWidget(self.status_bar_label)

        # layout
        layout = QGridLayout(self)
        layout.setSpacing(1)
        layout.addLayout(self.dimensions_layout, 0, 0, 1, 2)
        layout.addLayout(self.toolbar_layout, 1, 0, 1, 1)
        layout.addLayout(self.colorbar_layout, 1, 1, 3, 1)
        layout.addWidget(self.canvas, 2, 0, 1, 1)
        layout.addWidget(self.status_bar, 3, 0, 1, 1)
        layout.setRowStretch(2, 1)

    @property
    def grid_on(self):
        return self._grid_on

    @property
    def line_plotter(self):
        return self._line_plots

    @property
    def nonorthogonal_mode(self):
        return self.nonortho_transform is not None

    def create_axes_orthogonal(self, redraw_on_zoom=False):
        """Create a standard set of orthogonal axes
        :param redraw_on_zoom: If True then when scroll zooming the canvas is redrawn immediately
        """
        self.clear_figure()
        self.nonortho_transform = None
        self.ax = self.fig.add_subplot(111, projection='mantid')
        self.enable_zoom_on_mouse_scroll(redraw_on_zoom)
        if self.grid_on:
            self.ax.grid(self.grid_on)
        if self.line_plots_active:
            self.add_line_plots()

        self.plot_MDH = self.plot_MDH_orthogonal

        self.canvas.draw_idle()

    def create_axes_nonorthogonal(self, transform):
        self.clear_figure()
        self.set_nonorthogonal_transform(transform)
        self.ax = CurveLinearSubPlot(self.fig,
                                     1,
                                     1,
                                     1,
                                     grid_helper=GridHelperCurveLinear(
                                         (transform.tr, transform.inv_tr)))
        # don't redraw on zoom as the data is rebinned and has to be redrawn again anyway
        self.enable_zoom_on_mouse_scroll(redraw=False)
        self.set_grid_on()
        self.fig.add_subplot(self.ax)
        self.plot_MDH = self.plot_MDH_nonorthogonal

        self.canvas.draw_idle()

    def enable_zoom_on_mouse_scroll(self, redraw):
        """Enable zoom on scroll the mouse wheel for the created axes
        :param redraw: Pass through to redraw option in enable_zoom_on_scroll
        """
        self.canvas.enable_zoom_on_scroll(self.ax,
                                          redraw=redraw,
                                          toolbar=self.mpl_toolbar,
                                          callback=self.on_data_limits_changed)

    def add_line_plots(self, toolcls, exporter):
        """Assuming line plots are currently disabled, enable them on the current figure
        The image axes must have been created first.
        :param toolcls: Use this class to handle creating the plots
        :param exporter: Object defining methods to export cuts/roi
        """
        if self.line_plots_active:
            return

        self.line_plots_active = True
        self._line_plots = toolcls(LinePlots(self.ax, self.colorbar), exporter)
        self.status_bar_label.setText(self._line_plots.status_message())
        self.canvas.setFocus()
        self.mpl_toolbar.set_action_checked(ToolItemText.LINEPLOTS, True, trigger=False)

    def switch_line_plots_tool(self, toolcls, exporter):
        """Assuming line plots are currently enabled then switch the tool used to
        generate the plot curves.
        :param toolcls: Use this class to handle creating the plots
        """
        if not self.line_plots_active:
            return

        # Keep the same set of line plots axes but swap the selection tool
        plotter = self._line_plots.plotter
        plotter.delete_line_plot_lines()
        self._line_plots.disconnect()
        self._line_plots = toolcls(plotter, exporter)
        self.status_bar_label.setText(self._line_plots.status_message())
        self.canvas.setFocus()
        self.canvas.draw_idle()

    def remove_line_plots(self):
        """Assuming line plots are currently enabled, remove them from the current figure
        """
        if not self.line_plots_active:
            return

        self._line_plots.plotter.close()
        self.status_bar_label.clear()
        self._line_plots = None
        self.line_plots_active = False

    def plot_MDH_orthogonal(self, ws, **kwargs):
        """
        clears the plot and creates a new one using a MDHistoWorkspace
        """
        self.clear_image()
        self.image = self.ax.imshow(ws,
                                    origin='lower',
                                    aspect='auto',
                                    transpose=self.dimensions.transpose,
                                    norm=self.colorbar.get_norm(),
                                    **kwargs)
        # ensure the axes data limits are updated to match the
        # image. For example if the axes were zoomed and the
        # swap dimensions was clicked we need to restore the
        # appropriate extents to see the image in the correct place
        extent = self.image.get_extent()
        self.ax.set_xlim(extent[0], extent[1])
        self.ax.set_ylim(extent[2], extent[3])
        # Set the original data limits which get passed to the ImageInfoWidget so that
        # the mouse projection to data space is correct for MDH workspaces when zoomed/changing slices
        self._orig_lims = self.get_axes_limits()

        self.on_track_cursor_state_change(self.track_cursor_checked())

        self.draw_plot()

    def plot_MDH_nonorthogonal(self, ws, **kwargs):
        self.clear_image()
        self.image = pcolormesh_nonorthogonal(self.ax,
                                              ws,
                                              self.nonortho_transform.tr,
                                              transpose=self.dimensions.transpose,
                                              norm=self.colorbar.get_norm(),
                                              **kwargs)
        self.on_track_cursor_state_change(self.track_cursor_checked())

        # swapping dimensions in nonorthogonal mode currently resets back to the
        # full data limits as the whole axes has been recreated so we don't have
        # access to the original limits
        # pcolormesh clears any grid that was previously visible
        if self.grid_on:
            self.ax.grid(self.grid_on)
        self.draw_plot()

    def plot_matrix(self, ws, **kwargs):
        """
        clears the plot and creates a new one using a MatrixWorkspace keeping
        the axes limits that have already been set
        """
        # ensure view is correct if zoomed in while swapping dimensions
        # compute required extent and just have resampling imshow deal with it
        old_extent = None
        if self.image is not None:
            old_extent = self.image.get_extent()
            if self.image.transpose != self.dimensions.transpose:
                e1, e2, e3, e4 = old_extent
                old_extent = e3, e4, e1, e2

        self.clear_image()
        self.image = self.ax.imshow(ws,
                                    origin='lower',
                                    aspect='auto',
                                    interpolation='none',
                                    transpose=self.dimensions.transpose,
                                    norm=self.colorbar.get_norm(),
                                    extent=old_extent,
                                    **kwargs)
        self.on_track_cursor_state_change(self.track_cursor_checked())

        self.draw_plot()

    def clear_image(self):
        """Removes any image from the axes"""
        if self.image is not None:
            if self.line_plots_active:
                self._line_plots.plotter.delete_line_plot_lines()
            self.image_info_widget.cursorAt(DBLMAX, DBLMAX, DBLMAX)
            if hasattr(self.ax, "remove_artists_if"):
                self.ax.remove_artists_if(lambda art: art == self.image)
            else:
                self.image.remove()
            self.image = None

    def clear_figure(self):
        """Removes everything from the figure"""
        if self.line_plots_active:
            self._line_plots.plotter.close()
            self.line_plots_active = False
        self.image = None
        self.canvas.disable_zoom_on_scroll()
        self.fig.clf()
        self.ax = None

    def draw_plot(self):
        self.ax.set_title('')
        self.canvas.draw()
        if self.image:
            self.colorbar.set_mappable(self.image)
            self.colorbar.update_clim()
        self.mpl_toolbar.update()  # clear nav stack
        if self.line_plots_active:
            self._line_plots.plotter.delete_line_plot_lines()
            self._line_plots.plotter.update_line_plot_labels()

    def export_region(self, limits, cut):
        """
        React to a region selection that should be exported
        :param limits: 2-tuple of ((left, right), (bottom, top))
        :param cut: A str denoting which cuts to export.
        """
        self.presenter.export_region(limits, cut)

    def update_plot_data(self, data):
        """
        This just updates the plot data without creating a new plot. The extents
        can change if the data has been rebinned.
        """
        if self.nonortho_transform:
            self.image.set_array(data.T.ravel())
        else:
            self.image.set_data(data.T)
        self.colorbar.update_clim()

    def track_cursor_checked(self):
        return self.track_cursor.isChecked() if self.track_cursor else False

    def on_track_cursor_state_change(self, state):
        """
        Called to notify the current state of the track cursor box
        """
        if self._image_info_tracker is not None:
            self._image_info_tracker.disconnect()
        if self._line_plots is not None and not self._region_selection_on:
            self._line_plots.disconnect()

        self._image_info_tracker = ImageInfoTracker(image=self.image,
                                                    transform=self.nonortho_transform,
                                                    do_transform=self.nonorthogonal_mode,
                                                    widget=self.image_info_widget,
                                                    cursor_transform=self._orig_lims)

        if state:
            self._image_info_tracker.connect()
            if self._line_plots and not self._region_selection_on:
                self._line_plots.connect()
        else:
            self._image_info_tracker.disconnect()
            if self._line_plots and not self._region_selection_on:
                self._line_plots.disconnect()

    def on_home_clicked(self):
        """Reset the view to encompass all of the data"""
        self.presenter.show_all_data_clicked()

    def on_line_plots_toggle(self, state):
        """Switch state of the line plots"""
        self.presenter.line_plots(state)

    def on_region_selection_toggle(self, state):
        """Switch state of the region selection"""
        self.presenter.region_selection(state)
        self._region_selection_on = state
        # If state is off and track cursor is on, make sure line plots are re-connected to move cursor
        if not state and self.track_cursor_checked():
            if self._line_plots:
                self._line_plots.connect()

    def on_non_orthogonal_axes_toggle(self, state):
        """
        Switch state of the non-orthognal axes on/off
        """
        self.presenter.nonorthogonal_axes(state)

    def on_data_limits_changed(self):
        """
        React to when the data limits have changed
        """
        self.presenter.data_limits_changed()

    def deactivate_and_disable_tool(self, tool_text):
        """Deactivate a tool as if the control had been pressed and disable the functionality"""
        self.deactivate_tool(tool_text)
        self.disable_tool_button(tool_text)

    def activate_tool(self, tool_text):
        """Activate a given tool as if the control had been pressed"""
        self.mpl_toolbar.set_action_checked(tool_text, True)

    def deactivate_tool(self, tool_text):
        """Deactivate a given tool as if the tool button had been pressed"""
        self.mpl_toolbar.set_action_checked(tool_text, False)

    def enable_tool_button(self, tool_text):
        """Set a given tool button enabled so it can be interacted with"""
        self.mpl_toolbar.set_action_enabled(tool_text, True)

    def disable_tool_button(self, tool_text):
        """Set a given tool button disabled so it cannot be interacted with"""
        self.mpl_toolbar.set_action_enabled(tool_text, False)

    def get_axes_limits(self):
        """
        Return the limits on the image axes transformed into the nonorthogonal frame if appropriate
        """
        if self.image is None:
            return None
        else:
            xlim, ylim = self.ax.get_xlim(), self.ax.get_ylim()
            if self.nonorthogonal_mode:
                inv_tr = self.nonortho_transform.inv_tr
                # viewing axis y not aligned with plot axis
                xmin_p, ymax_p = inv_tr(xlim[0], ylim[1])
                xmax_p, ymin_p = inv_tr(xlim[1], ylim[0])
                xlim, ylim = (xmin_p, xmax_p), (ymin_p, ymax_p)
            return xlim, ylim

    def get_full_extent(self):
        """
        Return the full extent of image - only applicable for plots of matrix workspaces
        """
        if self.image and isinstance(self.image, samplingimage.SamplingImage):
            return self.image.get_full_extent()
        else:
            return None

    def set_axes_limits(self, xlim, ylim):
        """
        Set the view limits on the image axes to the given extents. Assume the
        limits are in the orthogonal frame.

        :param xlim: 2-tuple of (xmin, xmax)
        :param ylim: 2-tuple of (ymin, ymax)
        """
        self.ax.set_xlim(xlim)
        self.ax.set_ylim(ylim)

    def set_grid_on(self):
        """
        If not visible sets the grid visibility
        """
        if not self._grid_on:
            self._grid_on = True
            self.mpl_toolbar.set_action_checked(ToolItemText.GRID, state=self._grid_on)

    def set_nonorthogonal_transform(self, transform):
        """
        Set the transform for nonorthogonal axes mode
        :param transform: An object with a tr method to transform from nonorthognal
                          coordinates to display coordinates
        """
        self.nonortho_transform = transform

    def show_temporary_status_message(self, msg, timeout_ms):
        """
        Show a message in the status bar that disappears after a set period
        :param msg: A str message to display
        :param timeout_ms: Timeout in milliseconds to display the message for
        """
        self.status_bar.showMessage(msg, timeout_ms)

    def toggle_grid(self, state):
        """
        Toggle the visibility of the grid on the axes
        """
        self._grid_on = state
        self.ax.grid(self._grid_on)
        self.canvas.draw_idle()

    def mouse_release(self, event):
        if event.inaxes != self.ax:
            return
        self.canvas.setFocus()
        if event.button == 1:
            self._image_info_tracker.on_cursor_at(event.xdata, event.ydata)
            if self.line_plots_active and not self._region_selection_on:
                self._line_plots.on_cursor_at(event.xdata, event.ydata)
        if event.button == 3:
            self.on_home_clicked()

    def deactivate_zoom_pan(self):
        self.deactivate_tool(ToolItemText.PAN)
        self.deactivate_tool(ToolItemText.ZOOM)

    def update_data_clim(self):
        self.image.set_clim(self.colorbar.colorbar.mappable.get_clim())
        if self.line_plots_active:
            self._line_plots.plotter.update_line_plot_limits()
        self.canvas.draw_idle()

    def set_normalization(self, ws, **kwargs):
        normalize_by_bin_width, _ = get_normalize_by_bin_width(ws, self.ax, **kwargs)
        is_normalized = normalize_by_bin_width or ws.isDistribution()
        self.presenter.normalization = is_normalized
        if is_normalized:
            self.norm_opts.setCurrentIndex(1)
        else:
            self.norm_opts.setCurrentIndex(0)

    def get_default_scale_norm(self):
        scale = 'Linear'
        if self.conf is None:
            return scale

        if self.conf.has(SCALENORM):
            scale = self.conf.get(SCALENORM)

        if scale == 'Power' and self.conf.has(POWERSCALE):
            exponent = self.conf.get(POWERSCALE)
            scale = (scale, exponent)

        scale = "SymmetricLog10" if scale == 'Log' else scale
        return scale

    def scale_norm_changed(self):
        if self.conf is None:
            return

        scale = self.colorbar.norm.currentText()
        self.conf.set(SCALENORM, scale)

        if scale == 'Power':
            exponent = self.colorbar.powerscale_value
            self.conf.set(POWERSCALE, exponent)
Exemple #31
0
def plot2d(data, variables, filename):

    # default vales
    logscale_x = False
    logscale_y = False
    logable = True

    grid_bool = False

    axistop_bool = False
    axisright_bool = False
    axisbottom_bool = True
    axisleft_bool = True

    legend_outside = True

    colors = {}
    for i in range(0, len(variables)):
        colors[variables[i]] = ['w', 'b', 'g', 'r', 'c', 'm', 'y', 'k'][i]
    # intern parameters
    plot_range = 1. / 8  # means of two data series differ by this factor,
    # the scalng is defined ill

    # prepare data --->

    # check for appropriate format of input
    if (isinstance(variables, list)):
        for i in variables:
            if (not isinstance(i, str)):
                print('second argument must be a list of str')
                return None
    else:
        print('second argument must be a list')

    if (not isinstance(filename, str)):
        print('third argument must be of type str')
        return None
    if (not isinstance(data, list)):
        print('first argument must be of type list')
        return None
    for j in data[0]:
        if (not isinstance(j, float) and not isinstance(j, int)):
            print('data must be passed as a list of int or float')
            return None
    for i in data[1:]:
        for j in i:
            if (not isinstance(j, float) and not isinstance(j, int)):
                print('data must be passed as list of int or float')
                return None
            elif j <= 0 and logable:
                print('logscale impossible')
                logable = False  # to avoid using logscale

    #get number of rows and colums of data
    ncols = len(data)
    nrows = len(data[0])

    #check wether all rows have the same size and create df
    df = {}  # initialize empty dictionary similar to dataframe
    for i in range(0, ncols):
        if not len(data[i]) == nrows:
            print('missing values in data set')
            return None
        else:
            df[variables[i]] = data[i]

    # <--- prepare data

    # ---> analyse data

    # get lower and upper bounds of each variable
    bounds = {}

    for i in variables:
        [bounds['lower', i], bounds['upper', i]] = [min(df[i]), max(df[i])]

    # check whether magnitudes are approximately equal and use logscale if not
    means = [0] * (ncols - 1)
    for i in range(1, ncols):  # compute means of the columns
        means[i - 1] = np.mean(df[variables[i]])
    if min(means) / max(
            means
    ) < plot_range and logable:  # if variables have different magnitudes set
        print('ill scaling - use logscale')  # logscale
        logscale_y = True

    for i in range(
            1, ncols
    ):  # if one variable changes magnitude drastically set logscale
        if ((max(df[variables[i]]) - min(df[variables[i]])) != 0):
            temp = means[i - 1] / (max(df[variables[i]]) -
                                   min(df[variables[i]]))
            if temp < plot_range and logable and not logscale_y:
                print('very ill scaling - use logscale')
                logscale_y = True

    # <--- analyse data

    # plot --->
    fig = plt.figure(1)
    ax = Subplot(fig, 111)
    fig.add_subplot(ax)

    for i in variables[1:]:
        ax.scatter(df[variables[0]],
                   df[i],
                   label='$' + i + '$',
                   color=colors[i])
    # font

    # labels and legend
    ax.legend(loc='best')
    plt.xlabel(variables[0], **hfont)
    if legend_outside:
        box = ax.get_position()
        ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
        ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
    # logscale
    if logscale_y:
        plt.yscale('log')
    if logscale_x:
        plt.xscale('log')
    # grid
    plt.grid(grid_bool)

    # visible axis
    ax.axis["right"].set_visible(axisright_bool)
    ax.axis["top"].set_visible(axistop_bool)
    ax.axis["bottom"].set_visible(axisbottom_bool)
    ax.axis["left"].set_visible(axisleft_bool)

    # <--- plot

    # save plot --->
    pdfdirectory = filename + '.pdf'
    pgfdirectory = filename + '.pgf'
    fig.savefig(pdfdirectory)
    plt.savefig(pgfdirectory)
    # <--- save plot

    print('run successful')
    return None
Exemple #32
0
def plotSpikes(qdata,save=False,fname='hmmSorting.pdf',tuning=False,figsize=(10,6)):

    allSpikes = qdata['allSpikes'] 
    unitSpikes = qdata['unitSpikes']
    spikeIdx = qdata['spikeIdx']
    spikeIdx = qdata['unitTimePoints']
    units = qdata['unitTimePoints']
    spikeForms = qdata['spikeForms']
    channels = qdata['channels']
    uniqueIdx = qdata['uniqueIdx']
    samplingRate = qdata.get('samplingRate',30000.0)
    """
    mustClose = False
    if isinstance(dataFile,str):
        dataFile = h5py.File(dataFile,'r')
        mustClose = True
    data = dataFile['data'][:]
    """
    keys = np.array(units.keys())
    x = np.arange(32)[None,:] + 42*np.arange(spikeForms.shape[1])[:,None]
    xt = np.linspace(0,31,spikeForms.shape[-1])[None,:] + 42*np.arange(spikeForms.shape[1])[:,None]
    xch = 10 + 42*np.arange(len(channels))
    for c in units.keys():
        ymin,ymax = (5000,-5000)
        fig = plt.figure(figsize=figsize)
        fig.subplots_adjust(hspace=0.3)
        print "Unit: %s " %(str(c),)
        print "\t Plotting waveforms..."
        sys.stdout.flush()
        #allspikes = data[units[c][:,None]+np.arange(-10,22)[None,:],:]
        #allspikes = allSpikes[spikeIdx[c]]
        allspikes = qdata['unitSpikes'][c]
        otherunits = keys[keys!=c]
        #nonOverlapIdx = np.prod(np.array([~np.lib.arraysetops.in1d(spikeIdx[c],spikeIdx[c1]) for c1 in otherunits]),axis=0).astype(np.bool)
        #nonOverlapIdx = np.prod(np.array([pdist_threshold(spikeIdx[c],spikeIdx[c1],3) for c1 in otherunits]),axis=0).astype(np.bool)
        #nonOverlapIdx = uniqueIdx[c]
        nonOverlapIdx = qdata['nonOverlapIdx'][c]
        overlapIdx = np.lib.arraysetops.setdiff1d(np.arange(qdata['unitTimePoints'][c].shape[0]),nonOverlapIdx)
        #allspikes = allSpikes[np.lib.arraysetops.union1d(nonOverlapIdx,overlapIdx)]
        ax = Subplot(fig,2,3,1)
        fig.add_axes(ax)
        formatAxis(ax)
        #plt.plot(x.T,sp,'b')
        m = allspikes[:].mean(0)
        s = allspikes[:].std(0)
        plt.plot(x.T,m,'k',lw=1.5)
        #find the minimum point for this template
        ich = spikeForms[int(c)].min(1).argmin()
        ix = spikeForms[int(c)][ich,:].argmin()
        #plt.plot(x.T,spikeForms[int(c)][:,ix-10:ix+22].T,'r')
        plt.plot(x.T,np.roll(spikeForms[int(c)],10-ix,axis=1)[:,:32].T,'r')
        for i in xrange(x.shape[0]):
            plt.fill_between(x[i],m[:,i]-s[:,i],m[:,i]+s[:,i],color='b',alpha=0.5)
        yl = ax.get_ylim()
        ymin = min(ymin,yl[0])
        ymax = max(ymax,yl[1])
        ax.set_title('All spikes (%d)' % (allspikes.shape[0],))

        ax = Subplot(fig,2,3,2)
        fig.add_axes(ax)
        formatAxis(ax)
        if len(nonOverlapIdx)>0:
            m =  allspikes[:][nonOverlapIdx,:,:].mean(0)
            s =  allspikes[:][nonOverlapIdx,:,:].std(0)
            plt.plot(x.T,m,'k',lw=1.5)
            for i in xrange(x.shape[0]):
                plt.fill_between(x[i],m[:,i]-s[:,i],m[:,i]+s[:,i],color='b',alpha=0.5)
        #plt.plot(x.T,spikeForms[int(c)][:,ix-10:ix+22].T,'r')
        plt.plot(x.T,np.roll(spikeForms[int(c)],10-ix,axis=1)[:,:32].T,'r')
        yl = ax.get_ylim()
        ymin = min(ymin,yl[0])
        ymax = max(ymax,yl[1])
        #for sp in allspikes[nonOverlapIdx,:,:]:
        #    plt.plot(x.T,sp,'r')

        ax.set_title('Non-overlap spikes (%d)' %(nonOverlapIdx.shape[0],))
        ax = Subplot(fig,2,3,3)
        fig.add_axes(ax)
        formatAxis(ax)
        if len(overlapIdx)>0:
            m =  allspikes[:][overlapIdx,:,:].mean(0)
            s =  allspikes[:][overlapIdx,:,:].std(0)
            plt.plot(x.T,m,'k',lw=1.5)
            for i in xrange(x.shape[0]):
                plt.fill_between(x[i],m[:,i]-s[:,i],m[:,i]+s[:,i],color='b',alpha=0.5)
        #plt.plot(x.T,spikeForms[int(c)][:,ix-10:ix+22].T,'r')
        plt.plot(x.T,np.roll(spikeForms[int(c)],10-ix,axis=1)[:,:32].T,'r')
        yl = ax.get_ylim()
        ymin = min(ymin,yl[0])
        ymax = max(ymax,yl[1])
        #for sp in allspikes[~nonOverlapIdx,:,:]:
        #    plt.plot(x.T,sp,'g')
        ax.set_title('Overlap spikes (%d)' % ((overlapIdx).shape[0],))
        for a in fig.axes:
            a.set_ylim((ymin,ymax))
            a.set_xticks(xch)
            a.set_xticklabels(map(str,channels))
            a.set_xlabel('Channels')
        for a in fig.axes[1:]:
            a.set_yticklabels([])
        fig.axes[0].set_ylabel('Amplitude')
        """
        isi distribution
        """
        print "\t ISI distribution..."
        sys.stdout.flush()
        timepoints = qdata['unitTimePoints'][c][:]/(samplingRate/1000)
        if len(timepoints)<2:
            print "Too few spikes. Aborting..."
            continue 
        isi = np.log(np.diff(timepoints))
        n,b = np.histogram(isi,100)
        ax = Subplot(fig,2,3,4)
        fig.add_axes(ax)
        formatAxis(ax)
        ax.plot(b[:-1],n,'k')
        yl = ax.get_ylim()
        ax.vlines(0.0,0,yl[1],'r',lw=1.5)
        ax.set_xlabel('ISI [ms]')
        #get xticklabels
        xl,xh = int(np.round((b[0]-0.5)*2))/2,int(np.round((b[-1]+0.5)*2))/2
        xl = -0.5
        dx = np.round(10.0*(xh-xl)/5.0)/10
        xt_ = np.arange(xl,xh+1,dx)
        ax.set_xticks(xt_)
        ax.set_xticklabels(map(lambda s: r'$10^{%.1f}$' % (s,),xt_))

        """
        auto-correlogram
        """
        print "\t auto-correllogram..."
        sys.stdout.flush()
        if not 'autoCorr' in qdata:
            if isinstance(qdata,dict):
                qdata['autoCorr'] = {}
            else:
                qdata.create_group('autoCorr')
        if not c in qdata['autoCorr']:
            C = pdist_threshold2(timepoints,timepoints,50)
            qdata['autoCorr'][c] = C
            if not isinstance(qdata,dict):
                qdata.flush()
        else:
            C = qdata['autoCorr'][c][:]
        n,b = np.histogram(C[C!=0],np.arange(-50,50))
        ax = Subplot(fig,2,3,5)
        fig.add_axes(ax)
        formatAxis(ax)
        ax.plot(b[:-1],n,'k')
        ax.fill_betweenx([0,n.max()],-1.0,1.0,color='r',alpha=0.3)
        ax.set_xlabel('Lag [ms]')
        if tuning:
            print "\tPlotting tuning..."
            sys.stdout.flush()
            #attempt to get tuning for the current session, based on PWD
            stimCounts,isiCounts,angles,spikedata = gt.getTuning(sptrain=timepoints)        
            #reshape to number of orientations X number of reps, collapsing
            #across everything else
            #angles = np.append(angles,[angles[0]])
            C = stimCounts['0'].transpose((1,0,2,3))
            C = C.reshape(C.shape[0],C.size/C.shape[0])
            ax = plt.subplot(2,3,6,polar=True) 
            ax.errorbar(angles*np.pi/180,C.mean(1),C.std(1))

        if save:
            if not os.path.isabs(fname):
                fn = os.path.expanduser('~/Documents/research/figures/SpikeSorting/hmm/%s' % (fname.replace('.pdf','Unit%s.pdf' %(str(c),)),))
            else:
                fn = fname.replace('.pdf','Unit%s.pdf' %(str(c),))

            fig.savefig(fn,bbox='tight')

    if not save:
        plt.draw()
    """
Exemple #33
0
def plot_univariate_inequality(xdata,
                               inclusive=False,
                               raycolor='blue',
                               bgcolor='white',
                               xlim=None,
                               figsize=(5, 0.5),
                               figure=None,
                               title=None,
                               **kwargs):
    """Plot a chart of a univariate inequality ray with matplotlib
    
    Args:
        xdata (list, tuple): endpoints of the ray: ``[start, ..., end]``
        
    Kwargs:
        inclusive (bool): if True, draw a filled circle; if False, draw a circle without fill
        raycolor (str): matplotlib color of the line and markers
        bgcolor (str): matplotlib color for the background and circle without fill
        xlim (None, True, or list/tuple): if True, calculate defaults for xmin and xmax of the x-axis
        figsize (tuple): matplotlib figsize
        figure (None or matplotlib.figure.Figure): Figure to add a plot to
        title (None or str): Title to add the the plot
        kwargs: all other kwargs will be passed to `plt.figure()`
        
    Returns:
        matplotlib.figure.Figure: inequality figure
    """

    _xdata = sorted(xdata)
    xstart = _xdata[0]
    xend = _xdata[-1]
    lefttoright = xstart <= xend
    lefttoright2 = xdata[0] <= xdata[-1]

    fig1 = figure or plt.figure(figsize=figsize, facecolor=bgcolor, **kwargs)
    ax1 = Subplot(fig1, 111)
    fig1.add_subplot(ax1)

    style = {}
    style['linewidth'] = 4
    style['linestyle'] = 'solid'
    style['color'] = raycolor
    style['marker'] = 'o'
    style['markersize'] = 12
    style['markevery'] = [0] if lefttoright else [-1]
    style['markerfacecolor'] = raycolor if inclusive else bgcolor
    style['markeredgecolor'] = raycolor
    style['markeredgewidth'] = 4

    arrowstyle = {}
    arrowstyle['marker'] = '>' if lefttoright2 else '<'
    arrowstyle['markersize'] = 12
    arrowstyle['markerfacecolor'] = raycolor
    arrowstyle['markeredgecolor'] = raycolor
    arrowy = xdata[-1] if lefttoright else xdata[0]

    ax1.set(ylim=(-0.5, 1))

    if xlim is True:
        xlim = (float(xstart - 1), float(xend + 0.5))
    if xlim:
        ax1.set(xlim=xlim)

    ax1.axis["left"].set_visible(False)
    ax1.axis["right"].set_visible(False)
    ax1.axis["top"].set_visible(False)

    #ax1.axis["bottom"].set_axisline_style(axisline_style="->", size=2)
    ax1.plot(1, -0.5, ">k", transform=ax1.get_yaxis_transform(), clip_on=False)
    ax1.plot(0, -0.5, "<k", transform=ax1.get_yaxis_transform(), clip_on=False)

    _x = [xval for xval in xdata]
    _y = [0 for xval in xdata]
    plt.plot(_x, _y, **style)
    if title:
        ax1.set_title(title)
    plt.plot(arrowy, 0, **arrowstyle)
    return fig1
Exemple #34
0
class SliceViewerDataView(QWidget):
    """The view for the data portion of the sliceviewer"""
    def __init__(self, presenter, dims_info, can_normalise, parent=None):
        super().__init__(parent)

        self.presenter = presenter

        self.image = None
        self.line_plots = False
        self.can_normalise = can_normalise
        self.nonortho_tr = None

        # Dimension widget
        self.dimensions_layout = QHBoxLayout()
        self.dimensions = DimensionWidget(dims_info, parent=self)
        self.dimensions.dimensionsChanged.connect(
            self.presenter.dimensions_changed)
        self.dimensions.valueChanged.connect(self.presenter.slicepoint_changed)
        self.dimensions_layout.addWidget(self.dimensions)

        self.colorbar_layout = QVBoxLayout()

        # normalization options
        if can_normalise:
            self.norm_layout = QHBoxLayout()
            self.norm_label = QLabel("Normalization =")
            self.norm_layout.addWidget(self.norm_label)
            self.norm_opts = QComboBox()
            self.norm_opts.addItems(["None", "By bin width"])
            self.norm_opts.setToolTip("Normalization options")
            self.norm_layout.addWidget(self.norm_opts)
            self.colorbar_layout.addLayout(self.norm_layout)

        # MPL figure + colorbar
        self.mpl_layout = QHBoxLayout()
        self.fig = Figure()
        self.ax = None
        self._grid_on = False
        self.fig.set_facecolor(self.palette().window().color().getRgbF())
        self.canvas = FigureCanvas(self.fig)
        self.canvas.mpl_connect('motion_notify_event', self.mouse_move)
        self.create_axes_orthogonal()
        self.mpl_layout.addWidget(self.canvas)
        self.colorbar = ColorbarWidget(self)
        self.colorbar_layout.addWidget(self.colorbar)
        self.colorbar.colorbarChanged.connect(self.update_data_clim)
        self.colorbar.colorbarChanged.connect(self.update_line_plot_limits)
        self.mpl_layout.addLayout(self.colorbar_layout)

        # MPL toolbar
        self.mpl_toolbar = SliceViewerNavigationToolbar(self.canvas, self)
        self.mpl_toolbar.gridClicked.connect(self.toggle_grid)
        self.mpl_toolbar.linePlotsClicked.connect(self.line_plots_toggle)
        self.mpl_toolbar.plotOptionsChanged.connect(
            self.colorbar.mappable_changed)
        self.mpl_toolbar.nonOrthogonalClicked.connect(
            self.non_orthogonal_axes_toggle)

        # layout
        self.layout = QGridLayout(self)
        self.layout.addLayout(self.dimensions_layout, 0, 0)
        self.layout.addWidget(self.mpl_toolbar, 1, 0)
        self.layout.addLayout(self.mpl_layout, 2, 0)

    @property
    def grid_on(self):
        return self._grid_on

    @property
    def nonorthogonal_mode(self):
        return self.nonortho_tr is not None

    def create_axes_orthogonal(self):
        self.clear_figure()
        self.nonortho_tr = None
        self.ax = self.fig.add_subplot(111, projection='mantid')
        if self.grid_on:
            self.ax.grid()
        if self.line_plots:
            self.add_line_plots()
        self.plot_MDH = self.plot_MDH_orthogonal

        self.canvas.draw_idle()

    def create_axes_nonorthogonal(self, transform):
        self.clear_figure()
        self.set_nonorthogonal_transform(transform)
        self.ax = CurveLinearSubPlot(self.fig,
                                     1,
                                     1,
                                     1,
                                     grid_helper=GridHelperCurveLinear(
                                         (self.nonortho_tr, transform.inv_tr)))
        self.set_grid_on()
        self.fig.add_subplot(self.ax)
        self.plot_MDH = self.plot_MDH_nonorthogonal

        self.canvas.draw_idle()

    def add_line_plots(self):
        """Assuming line plots are currently disabled, enable them on the current figure
        The image axes must have been created first.
        """
        if self.line_plots:
            return
        image_axes = self.ax
        if image_axes is None:
            return

        # Create a new GridSpec and reposition the existing image Axes
        gs = gridspec.GridSpec(2,
                               2,
                               width_ratios=[1, 4],
                               height_ratios=[4, 1],
                               wspace=0.0,
                               hspace=0.0)
        image_axes.set_position(gs[1].get_position(self.fig))
        image_axes.xaxis.set_visible(False)
        image_axes.yaxis.set_visible(False)
        self.axx = self.fig.add_subplot(gs[3], sharex=image_axes)
        self.axx.yaxis.tick_right()
        self.axy = self.fig.add_subplot(gs[0], sharey=image_axes)
        self.axy.xaxis.tick_top()

        self.mpl_toolbar.update()  # sync list of axes in navstack
        self.canvas.draw_idle()

    def remove_line_plots(self):
        """Assuming line plots are currently enabled, remove them from the current figure
        """
        if not self.line_plots:
            return
        image_axes = self.ax
        if image_axes is None:
            return

        self.clear_line_plots()
        all_axes = self.fig.axes
        # The order is defined by the order of the add_subplot calls so we always want to remove
        # the last two Axes. Do it backwards to cope with the container size change
        all_axes[2].remove()
        all_axes[1].remove()

        gs = gridspec.GridSpec(1, 1)
        image_axes.set_position(gs[0].get_position(self.fig))
        image_axes.xaxis.set_visible(True)
        image_axes.yaxis.set_visible(True)
        self.axx, self.axy = None, None

        self.mpl_toolbar.update()  # sync list of axes in navstack
        self.canvas.draw_idle()

    def plot_MDH_orthogonal(self, ws, **kwargs):
        """
        clears the plot and creates a new one using a MDHistoWorkspace
        """
        self.clear_image()
        self.image = self.ax.imshow(ws,
                                    origin='lower',
                                    aspect='auto',
                                    transpose=self.dimensions.transpose,
                                    norm=self.colorbar.get_norm(),
                                    **kwargs)
        self.draw_plot()

    def plot_MDH_nonorthogonal(self, ws, **kwargs):
        self.clear_image()
        self.image = pcolormesh_nonorthogonal(
            self.ax,
            ws,
            self.nonortho_tr,
            transpose=self.dimensions.transpose,
            norm=self.colorbar.get_norm(),
            **kwargs)
        # pcolormesh clears any grid that was previously visible
        if self.grid_on:
            self.ax.grid()
        self.draw_plot()

    def plot_matrix(self, ws, **kwargs):
        """
        clears the plot and creates a new one using a MatrixWorkspace
        """
        self.clear_image()
        self.image = imshow_sampling(self.ax,
                                     ws,
                                     origin='lower',
                                     aspect='auto',
                                     interpolation='none',
                                     transpose=self.dimensions.transpose,
                                     norm=self.colorbar.get_norm(),
                                     **kwargs)
        self.image._resample_image()
        self.draw_plot()

    def clear_image(self):
        """Removes any image from the axes"""
        if self.image is not None:
            self.image.remove()
            self.image = None

    def clear_figure(self):
        """Removes everything from the figure"""
        self.image = None
        self._grid_on = False
        self.fig.clf()

    def draw_plot(self):
        self.ax.set_title('')
        self.colorbar.set_mappable(self.image)
        self.colorbar.update_clim()
        self.mpl_toolbar.update()  # clear nav stack
        self.clear_line_plots()
        self.canvas.draw_idle()

    def update_plot_data(self, data):
        """
        This just updates the plot data without creating a new plot
        """
        if self.nonortho_tr:
            self.image.set_array(data.T.ravel())
        else:
            self.image.set_data(data.T)
        self.colorbar.update_clim()

    def line_plots_toggle(self, state):
        self.presenter.line_plots(state)
        self.line_plots = state

    def non_orthogonal_axes_toggle(self, state):
        """
        Switch state of the non-orthognal axes on/off
        """
        self.presenter.nonorthogonal_axes(state)

    def enable_lineplots_button(self):
        """
        Enables line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.LINEPLOTS, True)

    def disable_lineplots_button(self):
        """
        Disabled line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.LINEPLOTS, False)

    def enable_peaks_button(self):
        """
        Enables line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.OVERLAYPEAKS, True)

    def disable_peaks_button(self):
        """
        Disables line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.OVERLAYPEAKS, False)

    def disable_nonorthogonal_axes_button(self):
        """
        Disables non-orthorognal axes functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.NONORTHOGONAL_AXES,
                                            False)

    def clear_line_plots(self):
        try:  # clear old plots
            del self.xfig
            del self.yfig
        except AttributeError:
            pass

    def update_data_clim(self):
        self.image.set_clim(self.colorbar.colorbar.mappable.get_clim())
        self.canvas.draw_idle()

    def update_line_plot_limits(self):
        if self.line_plots:
            self.axx.set_ylim(self.colorbar.cmin_value,
                              self.colorbar.cmax_value)
            self.axy.set_xlim(self.colorbar.cmin_value,
                              self.colorbar.cmax_value)

    def set_grid_on(self):
        """
        If not visible sets the grid visibility
        """
        if not self._grid_on:
            self.toggle_grid()

    def set_nonorthogonal_transform(self, transform):
        """
        Set the transform for nonorthogonal axes mode
        :param transform: An object with a tr method to transform from nonorthognal
                          coordinates to display coordinates
        """
        self.nonortho_tr = transform.tr

    def toggle_grid(self):
        """
        Toggle the visibility of the grid on the axes
        """
        self.ax.grid()
        self._grid_on = not self._grid_on
        self.canvas.draw_idle()

    def mouse_move(self, event):
        if self.line_plots and event.inaxes == self.ax:
            self.update_line_plots(event.xdata, event.ydata)

    def plot_x_line(self, x, y):
        try:
            self.xfig[0].set_data(x, y)
        except (AttributeError, IndexError):
            self.axx.clear()
            self.xfig = self.axx.plot(x, y)
            self.axx.set_xlabel(self.ax.get_xlabel())
            self.update_line_plot_limits()
        self.canvas.draw_idle()

    def plot_y_line(self, x, y):
        try:
            self.yfig[0].set_data(y, x)
        except (AttributeError, IndexError):
            self.axy.clear()
            self.yfig = self.axy.plot(y, x)
            self.axy.set_ylabel(self.ax.get_ylabel())
            self.update_line_plot_limits()
        self.canvas.draw_idle()

    def update_line_plots(self, x, y):
        xmin, xmax, ymin, ymax = self.image.get_extent()
        arr = self.image.get_array()
        data_extent = Bbox([[ymin, xmin], [ymax, xmax]])
        array_extent = Bbox([[0, 0], arr.shape[:2]])
        trans = BboxTransform(boxin=data_extent, boxout=array_extent)
        point = trans.transform_point([y, x])
        if any(np.isnan(point)):
            return
        i, j = point.astype(int)
        if 0 <= i < arr.shape[0]:
            self.plot_x_line(np.linspace(xmin, xmax, arr.shape[1]), arr[i, :])
        if 0 <= j < arr.shape[1]:
            self.plot_y_line(np.linspace(ymin, ymax, arr.shape[0]), arr[:, j])

    def set_normalization(self, ws, **kwargs):
        normalize_by_bin_width, _ = get_normalize_by_bin_width(
            ws, self.ax, **kwargs)
        is_normalized = normalize_by_bin_width or ws.isDistribution()
        if is_normalized:
            self.presenter.normalization = mantid.api.MDNormalization.VolumeNormalization
            self.norm_opts.setCurrentIndex(1)
        else:
            self.presenter.normalization = mantid.api.MDNormalization.NoNormalization
            self.norm_opts.setCurrentIndex(0)
def curvelinear_test1(fig):
    """
    grid for custom transform.
    """

    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y - x

    def inv_tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    # ax1 will have a ticks and gridlines defined by the given
    # transform (+ transData of the Axes). Note that the transform of
    # the Axes itself (i.e., transData) is not affected by the given
    # transform.

    fig.add_subplot(ax1)

    xx, yy = tr([3, 6], [5.0, 10.])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1.)
    ax1.set_xlim(0, 10.)
    ax1.set_ylim(0, 10.)

    ax1.axis["t"] = ax1.new_floating_axis(0, 3.)
    ax1.axis["t2"] = ax1.new_floating_axis(1, 7.)
    ax1.grid(True, zorder=0)
Exemple #36
0
class SliceViewerDataView(QWidget):
    """The view for the data portion of the sliceviewer"""
    def __init__(self, presenter, dims_info, can_normalise, parent=None):
        super().__init__(parent)

        self.presenter = presenter

        self.image = None
        self.line_plots = False
        self.can_normalise = can_normalise
        self.nonortho_tr = None
        self.ws_type = dims_info[0]['type']

        # Dimension widget
        self.dimensions_layout = QGridLayout()
        self.dimensions = DimensionWidget(dims_info, parent=self)
        self.dimensions.dimensionsChanged.connect(
            self.presenter.dimensions_changed)
        self.dimensions.valueChanged.connect(self.presenter.slicepoint_changed)
        self.dimensions_layout.addWidget(self.dimensions, 1, 0, 1, 1)

        self.colorbar_layout = QVBoxLayout()
        self.colorbar_layout.setContentsMargins(0, 0, 0, 0)
        self.colorbar_layout.setSpacing(0)

        self.image_info_widget = ImageInfoWidget(self.ws_type, self)
        self.track_cursor = QCheckBox("Track Cursor", self)
        self.track_cursor.setToolTip(
            "Update the image readout table when the cursor is over the plot. "
            "If unticked the table will update only when the plot is clicked")
        if self.ws_type == 'MDE':
            self.colorbar_layout.addWidget(self.image_info_widget,
                                           alignment=Qt.AlignCenter)
            self.colorbar_layout.addWidget(self.track_cursor)
        else:
            self.dimensions_layout.setHorizontalSpacing(10)
            self.dimensions_layout.addWidget(self.track_cursor, 0, 1,
                                             Qt.AlignRight)
            self.dimensions_layout.addWidget(self.image_info_widget, 1, 1)
        self.track_cursor.setChecked(True)

        # normalization options
        if can_normalise:
            self.norm_label = QLabel("Normalization")
            self.colorbar_layout.addWidget(self.norm_label)
            self.norm_opts = QComboBox()
            self.norm_opts.addItems(["None", "By bin width"])
            self.norm_opts.setToolTip("Normalization options")
            self.colorbar_layout.addWidget(self.norm_opts)

        # MPL figure + colorbar
        self.fig = Figure()
        self.ax = None
        self.axx, self.axy = None, None
        self.image = None
        self._grid_on = False
        self.fig.set_facecolor(self.palette().window().color().getRgbF())
        self.canvas = SliceViewerCanvas(self.fig)
        self.canvas.mpl_connect('motion_notify_event', self.mouse_move)
        self.canvas.mpl_connect('axes_leave_event', self.mouse_outside_image)
        self.canvas.mpl_connect('button_press_event', self.mouse_click)
        self.canvas.mpl_connect('button_release_event', self.mouse_release)

        self.colorbar_label = QLabel("Colormap")
        self.colorbar_layout.addWidget(self.colorbar_label)
        self.colorbar = ColorbarWidget(self)
        self.colorbar_layout.addWidget(self.colorbar)
        self.colorbar.colorbarChanged.connect(self.update_data_clim)
        self.colorbar.colorbarChanged.connect(self.update_line_plot_limits)
        # make width larger to fit image readout table
        if self.ws_type == 'MDE':
            self.colorbar.setMaximumWidth(155)

        # MPL toolbar
        self.toolbar_layout = QHBoxLayout()
        self.mpl_toolbar = SliceViewerNavigationToolbar(
            self.canvas, self, False)
        self.mpl_toolbar.gridClicked.connect(self.toggle_grid)
        self.mpl_toolbar.linePlotsClicked.connect(self.on_line_plots_toggle)
        self.mpl_toolbar.homeClicked.connect(self.on_home_clicked)
        self.mpl_toolbar.plotOptionsChanged.connect(
            self.colorbar.mappable_changed)
        self.mpl_toolbar.nonOrthogonalClicked.connect(
            self.on_non_orthogonal_axes_toggle)
        self.mpl_toolbar.zoomPanFinished.connect(self.on_data_limits_changed)
        self.toolbar_layout.addWidget(self.mpl_toolbar)

        # layout
        layout = QGridLayout(self)
        layout.setSpacing(1)
        layout.addLayout(self.dimensions_layout, 0, 0, 1, 2)
        layout.addLayout(self.toolbar_layout, 1, 0, 1, 2)
        layout.addWidget(self.canvas, 2, 0, 1, 1)
        layout.addLayout(self.colorbar_layout, 1, 1, 2, 1)
        layout.setRowStretch(2, 1)

    @property
    def grid_on(self):
        return self._grid_on

    @property
    def nonorthogonal_mode(self):
        return self.nonortho_tr is not None

    def create_axes_orthogonal(self, redraw_on_zoom=False):
        """Create a standard set of orthogonal axes
        :param redraw_on_zoom: If True then when scroll zooming the canvas is redrawn immediately
        """
        self.clear_figure()
        self.nonortho_tr = None
        self.ax = self.fig.add_subplot(111, projection='mantid')
        self.enable_zoom_on_mouse_scroll(redraw_on_zoom)
        if self.grid_on:
            self.ax.grid(self.grid_on)
        if self.line_plots:
            self.add_line_plots()

        self.plot_MDH = self.plot_MDH_orthogonal

        self.canvas.draw_idle()

    def create_axes_nonorthogonal(self, transform):
        self.clear_figure()
        self.set_nonorthogonal_transform(transform)
        self.ax = CurveLinearSubPlot(self.fig,
                                     1,
                                     1,
                                     1,
                                     grid_helper=GridHelperCurveLinear(
                                         (self.nonortho_tr, transform.inv_tr)))
        # don't redraw on zoom as the data is rebinned and has to be redrawn again anyway
        self.enable_zoom_on_mouse_scroll(redraw=False)
        self.set_grid_on()
        self.fig.add_subplot(self.ax)
        self.plot_MDH = self.plot_MDH_nonorthogonal

        self.canvas.draw_idle()

    def enable_zoom_on_mouse_scroll(self, redraw):
        """Enable zoom on scroll the mouse wheel for the created axes
        :param redraw: Pass through to redraw option in enable_zoom_on_scroll
        """
        self.canvas.enable_zoom_on_scroll(self.ax,
                                          redraw=redraw,
                                          toolbar=self.mpl_toolbar,
                                          callback=self.on_data_limits_changed)

    def add_line_plots(self):
        """Assuming line plots are currently disabled, enable them on the current figure
        The image axes must have been created first.
        """
        if self.line_plots:
            return

        self.line_plots = True
        image_axes = self.ax
        if image_axes is None:
            return

        # Create a new GridSpec and reposition the existing image Axes
        gs = gridspec.GridSpec(2,
                               2,
                               width_ratios=[1, 4],
                               height_ratios=[4, 1],
                               wspace=0.0,
                               hspace=0.0)
        image_axes.set_position(gs[1].get_position(self.fig))
        set_artist_property(image_axes.get_xticklabels(), visible=False)
        set_artist_property(image_axes.get_yticklabels(), visible=False)
        self.axx = self.fig.add_subplot(gs[3], sharex=image_axes)
        self.axx.yaxis.tick_right()
        self.axy = self.fig.add_subplot(gs[0], sharey=image_axes)
        self.axy.xaxis.tick_top()
        self.update_line_plot_labels()
        self.mpl_toolbar.update()  # sync list of axes in navstack
        self.canvas.draw_idle()

    def remove_line_plots(self):
        """Assuming line plots are currently enabled, remove them from the current figure
        """
        if not self.line_plots:
            return

        self.line_plots = False
        image_axes = self.ax
        if image_axes is None:
            return

        self.delete_line_plot_lines()
        all_axes = self.fig.axes
        # The order is defined by the order of the add_subplot calls so we always want to remove
        # the last two Axes. Do it backwards to cope with the container size change
        all_axes[2].remove()
        all_axes[1].remove()

        gs = gridspec.GridSpec(1, 1)
        image_axes.set_position(gs[0].get_position(self.fig))
        image_axes.xaxis.tick_bottom()
        image_axes.yaxis.tick_left()
        self.axx, self.axy = None, None

        self.mpl_toolbar.update()  # sync list of axes in navstack
        self.canvas.draw_idle()

    def plot_MDH_orthogonal(self, ws, **kwargs):
        """
        clears the plot and creates a new one using a MDHistoWorkspace
        """
        self.clear_image()
        self.image = self.ax.imshow(ws,
                                    origin='lower',
                                    aspect='auto',
                                    transpose=self.dimensions.transpose,
                                    norm=self.colorbar.get_norm(),
                                    **kwargs)
        # ensure the axes data limits are updated to match the
        # image. For example if the axes were zoomed and the
        # swap dimensions was clicked we need to restore the
        # appropriate extents to see the image in the correct place
        extent = self.image.get_extent()
        self.ax.set_xlim(extent[0], extent[1])
        self.ax.set_ylim(extent[2], extent[3])

        self.draw_plot()

    def plot_MDH_nonorthogonal(self, ws, **kwargs):
        self.clear_image()
        self.image = pcolormesh_nonorthogonal(
            self.ax,
            ws,
            self.nonortho_tr,
            transpose=self.dimensions.transpose,
            norm=self.colorbar.get_norm(),
            **kwargs)
        # swapping dimensions in nonorthogonal mode currently resets back to the
        # full data limits as the whole axes has been recreated so we don't have
        # access to the original limits
        # pcolormesh clears any grid that was previously visible
        if self.grid_on:
            self.ax.grid(self.grid_on)
        self.draw_plot()

    def plot_matrix(self, ws, **kwargs):
        """
        clears the plot and creates a new one using a MatrixWorkspace keeping
        the axes limits that have already been set
        """
        # ensure view is correct if zoomed in while swapping dimensions
        # compute required extent and just have resampling imshow deal with it
        old_extent = None
        if self.image is not None:
            old_extent = self.image.get_extent()
            if self.image.transpose != self.dimensions.transpose:
                e1, e2, e3, e4 = old_extent
                old_extent = e3, e4, e1, e2

        self.clear_image()
        self.image = imshow_sampling(self.ax,
                                     ws,
                                     origin='lower',
                                     aspect='auto',
                                     interpolation='none',
                                     transpose=self.dimensions.transpose,
                                     norm=self.colorbar.get_norm(),
                                     extent=old_extent,
                                     **kwargs)

        self.draw_plot()

    def clear_image(self):
        """Removes any image from the axes"""
        if self.image is not None:
            if self.line_plots:
                self.delete_line_plot_lines()
            self.image_info_widget.updateTable(DBLMAX, DBLMAX, DBLMAX)
            self.image.remove()
            self.image = None

    def clear_figure(self):
        """Removes everything from the figure"""
        if self.line_plots:
            self.delete_line_plot_lines()
            self.axx, self.axy = None, None
        self.image = None
        self.canvas.disable_zoom_on_scroll()
        self.fig.clf()
        self.ax = None

    def draw_plot(self):
        self.ax.set_title('')
        self.colorbar.set_mappable(self.image)
        self.colorbar.update_clim()
        self.mpl_toolbar.update()  # clear nav stack
        self.delete_line_plot_lines()
        self.update_line_plot_labels()
        self.canvas.draw_idle()

    def select_zoom(self):
        """Select the zoom control on the toolbar"""
        self.mpl_toolbar.zoom()

    def update_plot_data(self, data):
        """
        This just updates the plot data without creating a new plot. The extents
        can change if the data has been rebinned
        """
        if self.nonortho_tr:
            self.image.set_array(data.T.ravel())
        else:
            self.image.set_data(data.T)
        self.colorbar.update_clim()

    def on_home_clicked(self):
        """Reset the view to encompass all of the data"""
        self.presenter.show_all_data_requested()

    def on_line_plots_toggle(self, state):
        self.presenter.line_plots(state)

    def on_non_orthogonal_axes_toggle(self, state):
        """
        Switch state of the non-orthognal axes on/off
        """
        self.presenter.nonorthogonal_axes(state)

    def on_data_limits_changed(self):
        """
        React to when the data limits have changed
        """
        self.presenter.data_limits_changed()

    def enable_lineplots_button(self):
        """
        Enables line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.LINEPLOTS, True)

    def disable_lineplots_button(self):
        """
        Disabled line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.LINEPLOTS, False)

    def enable_peaks_button(self):
        """
        Enables line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.OVERLAYPEAKS, True)

    def disable_peaks_button(self):
        """
        Disables line plots functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.OVERLAYPEAKS, False)

    def enable_nonorthogonal_axes_button(self):
        """
        Enables access to non-orthogonal axes functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.NONORTHOGONAL_AXES,
                                            True)

    def disable_nonorthogonal_axes_button(self):
        """
        Disables non-orthorognal axes functionality
        """
        self.mpl_toolbar.set_action_enabled(ToolItemText.NONORTHOGONAL_AXES,
                                            state=False)

    def delete_line_plot_lines(self):
        try:  # clear old plots
            try:
                self.xfig.remove()
                self.yfig.remove()
            except ValueError:
                pass
            del self.xfig
            del self.yfig
        except AttributeError:
            pass

    def get_axes_limits(self):
        """
        Return the limits of the image axes or None if no image yet exists
        """
        if self.image is None:
            return None
        else:
            return self.ax.get_xlim(), self.ax.get_ylim()

    def set_axes_limits(self, xlim, ylim):
        """
        Set the view limits on the image axes to the given extents
        :param xlim: 2-tuple of (xmin, xmax)
        :param ylim: 2-tuple of (ymin, ymax)
        """
        self.ax.set_xlim(xlim)
        self.ax.set_ylim(ylim)

    def set_grid_on(self):
        """
        If not visible sets the grid visibility
        """
        if not self._grid_on:
            self._grid_on = True
            self.mpl_toolbar.set_action_checked(ToolItemText.GRID,
                                                state=self._grid_on)

    def set_nonorthogonal_transform(self, transform):
        """
        Set the transform for nonorthogonal axes mode
        :param transform: An object with a tr method to transform from nonorthognal
                          coordinates to display coordinates
        """
        self.nonortho_tr = transform.tr

    def toggle_grid(self, state):
        """
        Toggle the visibility of the grid on the axes
        """
        self._grid_on = state
        self.ax.grid(self._grid_on)
        self.canvas.draw_idle()

    def mouse_move(self, event):
        if event.inaxes == self.ax:
            signal = self.update_image_data(event.xdata, event.ydata,
                                            self.line_plots)
            if self.track_cursor.checkState() == Qt.Checked:
                self.update_image_table_widget(event.xdata, event.ydata,
                                               signal)

    def mouse_outside_image(self, _):
        """
        Indicates that the mouse have moved outside of an axes.
        We clear the line plots so that it is not confusing what they mean.
        """
        if self.line_plots:
            self.delete_line_plot_lines()
            self.canvas.draw_idle()

    def mouse_click(self, event):
        if self.track_cursor.checkState() == Qt.Unchecked \
                and event.inaxes == self.ax and event.button == 1:
            signal = self.update_image_data(event.xdata, event.ydata)
            self.update_image_table_widget(event.xdata, event.ydata, signal)

    def mouse_release(self, event):
        if event.button == 3 and event.inaxes == self.ax:
            self.on_home_clicked()

    def update_image_table_widget(self, xdata, ydata, signal):
        if signal is not None:
            if self.dimensions.transpose and self.ws_type == "MATRIX":
                self.image_info_widget.updateTable(ydata, xdata, signal)
            else:
                self.image_info_widget.updateTable(xdata, ydata, signal)

    def plot_x_line(self, x, y):
        try:
            self.xfig.set_data(x, y)
        except (AttributeError, IndexError):
            self.axx.clear()
            self.xfig = self.axx.plot(x, y, scalex=False)[0]
            self.update_line_plot_labels()
            self.update_line_plot_limits()
        self.canvas.draw_idle()

    def plot_y_line(self, x, y):
        try:
            self.yfig.set_data(y, x)
        except (AttributeError, IndexError):
            self.axy.clear()
            self.yfig = self.axy.plot(y, x, scaley=False)[0]
            self.update_line_plot_labels()
            self.update_line_plot_limits()
        self.canvas.draw_idle()

    def update_data_clim(self):
        self.image.set_clim(self.colorbar.colorbar.mappable.get_clim())
        self.canvas.draw_idle()

    def update_line_plot_limits(self):
        try:  # set line plot intensity axes to match colorbar limits
            self.axx.set_ylim(self.colorbar.cmin_value,
                              self.colorbar.cmax_value)
            self.axy.set_xlim(self.colorbar.cmin_value,
                              self.colorbar.cmax_value)
        except AttributeError:
            pass

    def update_line_plot_labels(self):
        try:  # ensure plot labels are in sync with main axes
            self.axx.set_xlabel(self.ax.get_xlabel())
            self.axy.set_ylabel(self.ax.get_ylabel())
        except AttributeError:
            pass

    def update_image_data(self, x, y, update_line_plot=False):
        xmin, xmax, ymin, ymax = self.image.get_extent()
        arr = self.image.get_array()
        data_extent = Bbox([[ymin, xmin], [ymax, xmax]])
        array_extent = Bbox([[0, 0], arr.shape[:2]])
        trans = BboxTransform(boxin=data_extent, boxout=array_extent)
        point = trans.transform_point([y, x])
        if any(np.isnan(point)):
            return
        i, j = point.astype(int)

        if update_line_plot:
            if 0 <= i < arr.shape[0]:
                self.plot_x_line(np.linspace(xmin, xmax, arr.shape[1]),
                                 arr[i, :])
            if 0 <= j < arr.shape[1]:
                self.plot_y_line(np.linspace(ymin, ymax, arr.shape[0]), arr[:,
                                                                            j])

        # Clip the coordinates at array bounds
        if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]):
            return None
        else:
            return arr[i, j]

    def set_normalization(self, ws, **kwargs):
        normalize_by_bin_width, _ = get_normalize_by_bin_width(
            ws, self.ax, **kwargs)
        is_normalized = normalize_by_bin_width or ws.isDistribution()
        if is_normalized:
            self.presenter.normalization = mantid.api.MDNormalization.VolumeNormalization
            self.norm_opts.setCurrentIndex(1)
        else:
            self.presenter.normalization = mantid.api.MDNormalization.NoNormalization
            self.norm_opts.setCurrentIndex(0)
Exemple #37
0
class DGSPlannerGUI(QtWidgets.QWidget):
    def __init__(self, parent=None, window_flags=None, ol=None):
        # pylint: disable=unused-argument,super-on-old-class
        super(DGSPlannerGUI, self).__init__(parent)
        if window_flags:
            self.setWindowFlags(window_flags)
        # OrientedLattice
        if ValidateOL(ol):
            self.ol = ol
        else:
            self.ol = mantid.geometry.OrientedLattice()
        self.masterDict = dict()  # holds info about instrument and ranges
        self.updatedInstrument = False
        self.instrumentWAND = False
        self.updatedOL = False
        self.wg = None  # workspace group
        self.instrumentWidget = InstrumentSetupWidget.InstrumentSetupWidget(
            self)
        self.setLayout(QtWidgets.QHBoxLayout())
        controlLayout = QtWidgets.QVBoxLayout()
        geometryBox = QtWidgets.QGroupBox("Instrument Geometry")
        plotBox = QtWidgets.QGroupBox("Plot Axes")
        geometryBoxLayout = QtWidgets.QVBoxLayout()
        geometryBoxLayout.addWidget(self.instrumentWidget)
        geometryBox.setLayout(geometryBoxLayout)
        controlLayout.addWidget(geometryBox)
        self.ublayout = QtWidgets.QHBoxLayout()
        self.classic = ClassicUBInputWidget.ClassicUBInputWidget(self.ol)
        self.ublayout.addWidget(self.classic,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        self.matrix = MatrixUBInputWidget.MatrixUBInputWidget(self.ol)
        self.ublayout.addWidget(self.matrix,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        sampleBox = QtWidgets.QGroupBox("Sample")
        sampleBox.setLayout(self.ublayout)
        controlLayout.addWidget(sampleBox)
        self.dimensionWidget = DimensionSelectorWidget.DimensionSelectorWidget(
            self)
        plotBoxLayout = QtWidgets.QVBoxLayout()
        plotBoxLayout.addWidget(self.dimensionWidget)
        plotControlLayout = QtWidgets.QGridLayout()
        self.plotButton = QtWidgets.QPushButton("Plot", self)
        self.oplotButton = QtWidgets.QPushButton("Overplot", self)
        self.helpButton = QtWidgets.QPushButton("?", self)
        self.colorLabel = QtWidgets.QLabel('Color by angle', self)
        self.colorButton = QtWidgets.QCheckBox(self)
        self.colorButton.toggle()
        self.aspectLabel = QtWidgets.QLabel('Aspect ratio 1:1', self)
        self.aspectButton = QtWidgets.QCheckBox(self)
        self.saveButton = QtWidgets.QPushButton("Save Figure", self)
        plotControlLayout.addWidget(self.plotButton, 0, 0)
        plotControlLayout.addWidget(self.oplotButton, 0, 1)
        plotControlLayout.addWidget(self.colorLabel, 0, 2,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.colorButton, 0, 3)
        plotControlLayout.addWidget(self.aspectLabel, 0, 4,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.aspectButton, 0, 5)
        plotControlLayout.addWidget(self.helpButton, 0, 6)
        plotControlLayout.addWidget(self.saveButton, 0, 7)
        plotBoxLayout.addLayout(plotControlLayout)
        plotBox = QtWidgets.QGroupBox("Plot Axes")
        plotBox.setLayout(plotBoxLayout)
        controlLayout.addWidget(plotBox)
        self.layout().addLayout(controlLayout)

        # figure
        self.figure = Figure()
        self.figure.patch.set_facecolor('white')
        self.canvas = FigureCanvas(self.figure)
        self.grid_helper = GridHelperCurveLinear((self.tr, self.inv_tr))
        self.trajfig = Subplot(self.figure,
                               1,
                               1,
                               1,
                               grid_helper=self.grid_helper)
        if matplotlib.compare_versions('2.1.0', matplotlib.__version__):
            self.trajfig.hold(
                True)  # hold is deprecated since 2.1.0, true by default
        self.figure.add_subplot(self.trajfig)
        self.toolbar = MantidNavigationToolbar(self.canvas, self)
        figureLayout = QtWidgets.QVBoxLayout()
        figureLayout.addWidget(self.toolbar, 0)
        figureLayout.addWidget(self.canvas, 1)
        self.layout().addLayout(figureLayout)
        self.needToClear = False
        self.saveDir = ''

        # connections
        self.matrix.UBmodel.changed.connect(self.updateUB)
        self.matrix.UBmodel.changed.connect(self.classic.updateOL)
        self.classic.changed.connect(self.matrix.UBmodel.updateOL)
        self.classic.changed.connect(self.updateUB)
        self.instrumentWidget.changed.connect(self.updateParams)
        self.instrumentWidget.getInstrumentComboBox().activated[str].connect(
            self.instrumentUpdateEvent)
        self.instrumentWidget.getEditEi().textChanged.connect(
            self.eiWavelengthUpdateEvent)
        self.dimensionWidget.changed.connect(self.updateParams)
        self.plotButton.clicked.connect(self.updateFigure)
        self.oplotButton.clicked.connect(self.updateFigure)
        self.helpButton.clicked.connect(self.help)
        self.saveButton.clicked.connect(self.save)
        # force an update of values
        self.instrumentWidget.updateAll()
        self.dimensionWidget.updateChanges()
        # help
        self.assistant_process = QtCore.QProcess(self)
        # pylint: disable=protected-access
        self.mantidplot_name = 'DGS Planner'
        # control for cancel button
        self.iterations = 0
        self.progress_canceled = False

        # register startup
        mantid.UsageService.registerFeatureUsage(
            mantid.kernel.FeatureType.Interface, "DGSPlanner", False)

    @QtCore.Slot(mantid.geometry.OrientedLattice)
    def updateUB(self, ol):
        self.ol = ol
        self.updatedOL = True
        self.trajfig.clear()

    def eiWavelengthUpdateEvent(self):
        if self.masterDict['instrument'] == 'WAND\u00B2':
            ei = UnitConversion.run('Wavelength', 'Energy',
                                    self.masterDict['Ei'], 0, 0, 0, Elastic, 0)
            offset = ei * 0.01
            lowerBound = -offset
            upperBound = offset
            self.dimensionWidget.set_editMin4(lowerBound)
            self.dimensionWidget.set_editMax4(upperBound)

    def instrumentUpdateEvent(self):
        if self.masterDict['instrument'] == 'WAND\u00B2':
            self.instrumentWAND = True
            # change the ui accordingly
            self.dimensionWidget.toggleDeltaE(False)
            self.instrumentWidget.setLabelEi('Input Wavelength')
            self.instrumentWidget.setEiVal(str(1.488))

            self.instrumentWidget.setGoniometerNames(['s1', 'sgl', 'sgu'])
            self.instrumentWidget.setGoniometerDirections(
                ['0,1,0', '1,0,0', '0,0,1'])
            self.instrumentWidget.setGoniometerRotationSense([1, -1, -1])
            self.instrumentWidget.updateAll()

            self.eiWavelengthUpdateEvent()
        else:
            if self.instrumentWAND:
                self.instrumentWAND = False
                self.dimensionWidget.toggleDeltaE(True)
                self.instrumentWidget.setLabelEi('Incident Energy')
                self.instrumentWidget.setEiVal(str(10.0))

                self.instrumentWidget.setGoniometerNames(['psi', 'gl', 'gs'])
                self.instrumentWidget.setGoniometerDirections(
                    ['0,1,0', '0,0,1', '1,0,0'])
                self.instrumentWidget.setGoniometerRotationSense([1, 1, 1])
                self.instrumentWidget.updateAll()

    @QtCore.Slot(dict)
    def updateParams(self, d):
        if self.sender() is self.instrumentWidget:
            self.updatedInstrument = True
        if 'dimBasis' in d and 'dimBasis' in self.masterDict and d[
                'dimBasis'] != self.masterDict['dimBasis']:
            self.needToClear = True
        if 'dimIndex' in d and 'dimIndex' in self.masterDict and d[
                'dimIndex'] != self.masterDict['dimIndex']:
            self.needToClear = True
        self.masterDict.update(copy.deepcopy(d))

    def help(self):
        show_interface_help(self.mantidplot_name,
                            self.assistant_process,
                            area='direct')

    def closeEvent(self, event):
        self.assistant_process.close()
        self.assistant_process.waitForFinished()
        event.accept()

    def _create_goniometer_workspaces(self, gonioAxis0values, gonioAxis1values,
                                      gonioAxis2values, progressDialog):
        groupingStrings = []
        i = 0
        for g0 in gonioAxis0values:
            for g1 in gonioAxis1values:
                for g2 in gonioAxis2values:
                    name = "__temp_instrument" + str(i)
                    i += 1
                    progressDialog.setValue(i)
                    progressDialog.setLabelText(
                        "Creating workspace %d of %d..." %
                        (i, self.iterations))
                    QtWidgets.qApp.processEvents()
                    if progressDialog.wasCanceled():
                        self.progress_canceled = True
                        progressDialog.close()
                        return None

                    groupingStrings.append(name)
                    mantid.simpleapi.CloneWorkspace("__temp_instrument",
                                                    OutputWorkspace=name)
                    mantid.simpleapi.SetGoniometer(
                        Workspace=name,
                        Axis0=str(g0) + "," + self.masterDict['gonioDirs'][0] +
                        "," + str(self.masterDict['gonioSenses'][0]),
                        Axis1=str(g1) + "," + self.masterDict['gonioDirs'][1] +
                        "," + str(self.masterDict['gonioSenses'][1]),
                        Axis2=str(g2) + "," + self.masterDict['gonioDirs'][2] +
                        "," + str(self.masterDict['gonioSenses'][2]))
        return groupingStrings

    # pylint: disable=too-many-locals
    def updateFigure(self):  # noqa: C901
        # pylint: disable=too-many-branches
        if self.updatedInstrument or self.progress_canceled:
            self.progress_canceled = False
            # get goniometer settings first
            gonioAxis0values = numpy.arange(
                self.masterDict['gonioMinvals'][0],
                self.masterDict['gonioMaxvals'][0] +
                0.1 * self.masterDict['gonioSteps'][0],
                self.masterDict['gonioSteps'][0])
            gonioAxis1values = numpy.arange(
                self.masterDict['gonioMinvals'][1],
                self.masterDict['gonioMaxvals'][1] +
                0.1 * self.masterDict['gonioSteps'][1],
                self.masterDict['gonioSteps'][1])
            gonioAxis2values = numpy.arange(
                self.masterDict['gonioMinvals'][2],
                self.masterDict['gonioMaxvals'][2] +
                0.1 * self.masterDict['gonioSteps'][2],
                self.masterDict['gonioSteps'][2])
            self.iterations = len(gonioAxis0values) * len(
                gonioAxis1values) * len(gonioAxis2values)
            if self.iterations > 10:
                reply = QtWidgets.QMessageBox.warning(
                    self, 'Goniometer',
                    "More than 10 goniometer settings. This might be long.\n"
                    "Are you sure you want to proceed?",
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                    QtWidgets.QMessageBox.No)
                if reply == QtWidgets.QMessageBox.No:
                    return

            if self.wg is not None:
                mantid.simpleapi.DeleteWorkspace(self.wg)

            instrumentName = self.masterDict['instrument']
            if instrumentName == 'WAND\u00B2':
                instrumentName = 'WAND'

            mantid.simpleapi.LoadEmptyInstrument(
                mantid.api.ExperimentInfo.getInstrumentFilename(
                    instrumentName),
                OutputWorkspace="__temp_instrument")
            if self.masterDict['instrument'] == 'HYSPEC':
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",
                                              LogName='msd',
                                              LogText='1798.5',
                                              LogType='Number Series')
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",
                                              LogName='s2',
                                              LogText=str(
                                                  self.masterDict['S2']),
                                              LogType='Number Series')
                mantid.simpleapi.LoadInstrument(Workspace="__temp_instrument",
                                                RewriteSpectraMap=True,
                                                InstrumentName="HYSPEC")
            elif self.masterDict['instrument'] == 'EXED':
                mantid.simpleapi.RotateInstrumentComponent(
                    Workspace="__temp_instrument",
                    ComponentName='Tank',
                    Y=1,
                    Angle=str(self.masterDict['S2']),
                    RelativeRotation=False)
            elif instrumentName == 'WAND':
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",
                                              LogName='HB2C:Mot:s2.RBV',
                                              LogText=str(
                                                  self.masterDict['S2']),
                                              LogType='Number Series')
                mantid.simpleapi.AddSampleLog(Workspace="__temp_instrument",
                                              LogName='HB2C:Mot:detz.RBV',
                                              LogText=str(
                                                  self.masterDict['DetZ']),
                                              LogType='Number Series')
                mantid.simpleapi.LoadInstrument(Workspace="__temp_instrument",
                                                RewriteSpectraMap=True,
                                                InstrumentName="WAND")
            # masking
            if 'maskFilename' in self.masterDict and len(
                    self.masterDict['maskFilename'].strip()) > 0:
                try:
                    __maskWS = mantid.simpleapi.Load(
                        self.masterDict['maskFilename'])
                    mantid.simpleapi.MaskDetectors(
                        Workspace="__temp_instrument",
                        MaskedWorkspace=__maskWS)
                except (ValueError, RuntimeError) as e:
                    reply = QtWidgets.QMessageBox.critical(
                        self, 'Error',
                        "The following error has occurred in loading the mask:\n"
                        + str(e) + "\nDo you want to continue without mask?",
                        QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                        QtWidgets.QMessageBox.No)
                    if reply == QtWidgets.QMessageBox.No:
                        return
            if self.masterDict['makeFast']:
                sp = list(
                    range(
                        mantid.mtd["__temp_instrument"].getNumberHistograms()))
                tomask = sp[1::4] + sp[2::4] + sp[3::4]
                mantid.simpleapi.MaskDetectors("__temp_instrument",
                                               SpectraList=tomask)

            progressDialog = QtWidgets.QProgressDialog(self)
            progressDialog.setMinimumDuration(0)
            progressDialog.setCancelButtonText("&Cancel")
            progressDialog.setRange(0, self.iterations)
            progressDialog.setWindowTitle("DGSPlanner progress")

            groupingStrings = self._create_goniometer_workspaces(
                gonioAxis0values, gonioAxis1values, gonioAxis2values,
                progressDialog)
            if groupingStrings is None:
                return

            progressDialog.close()
            mantid.simpleapi.DeleteWorkspace("__temp_instrument")
            self.wg = mantid.simpleapi.GroupWorkspaces(
                groupingStrings, OutputWorkspace="__temp_instrument")
            self.updatedInstrument = False
        # set the UB
        if self.updatedOL or not self.wg[0].sample().hasOrientedLattice():
            mantid.simpleapi.SetUB(self.wg, UB=self.ol.getUB())
            self.updatedOL = False
        # calculate coverage
        dimensions = ['Q1', 'Q2', 'Q3', 'DeltaE']
        progressDialog = QtWidgets.QProgressDialog(self)
        progressDialog.setMinimumDuration(0)
        progressDialog.setCancelButtonText("&Cancel")
        progressDialog.setRange(0, self.iterations)
        progressDialog.setWindowTitle("DGSPlanner progress")

        if self.masterDict['instrument'] == 'WAND\u00B2':
            ei = UnitConversion.run('Wavelength', 'Energy',
                                    self.masterDict['Ei'], 0, 0, 0, Elastic, 0)
        else:
            ei = self.masterDict['Ei']

        for i in range(self.iterations):
            progressDialog.setValue(i)
            progressDialog.setLabelText("Calculating orientation %d of %d..." %
                                        (i, self.iterations))
            QtWidgets.qApp.processEvents()
            if progressDialog.wasCanceled():
                self.progress_canceled = True
                progressDialog.close()
                return

            __mdws = mantid.simpleapi.CalculateCoverageDGS(
                self.wg[i],
                Q1Basis=self.masterDict['dimBasis'][0],
                Q2Basis=self.masterDict['dimBasis'][1],
                Q3Basis=self.masterDict['dimBasis'][2],
                IncidentEnergy=ei,
                Dimension1=dimensions[self.masterDict['dimIndex'][0]],
                Dimension1Min=float2Input(self.masterDict['dimMin'][0]),
                Dimension1Max=float2Input(self.masterDict['dimMax'][0]),
                Dimension1Step=float2Input(self.masterDict['dimStep'][0]),
                Dimension2=dimensions[self.masterDict['dimIndex'][1]],
                Dimension2Min=float2Input(self.masterDict['dimMin'][1]),
                Dimension2Max=float2Input(self.masterDict['dimMax'][1]),
                Dimension2Step=float2Input(self.masterDict['dimStep'][1]),
                Dimension3=dimensions[self.masterDict['dimIndex'][2]],
                Dimension3Min=float2Input(self.masterDict['dimMin'][2]),
                Dimension3Max=float2Input(self.masterDict['dimMax'][2]),
                Dimension4=dimensions[self.masterDict['dimIndex'][3]],
                Dimension4Min=float2Input(self.masterDict['dimMin'][3]),
                Dimension4Max=float2Input(self.masterDict['dimMax'][3]))

            if i == 0:
                intensity = __mdws.getSignalArray(
                )[:, :, 0, 0] * 1.  # to make it writeable
            else:
                if self.colorButton.isChecked():
                    tempintensity = __mdws.getSignalArray()[:, :, 0, 0]
                    intensity[numpy.where(tempintensity > 0)] = i + 1.
                else:
                    tempintensity = __mdws.getSignalArray()[:, :, 0, 0]
                    intensity[numpy.where(tempintensity > 0)] = 1.
        progressDialog.close()
        x = numpy.linspace(
            __mdws.getDimension(0).getMinimum(),
            __mdws.getDimension(0).getMaximum(), intensity.shape[0])
        y = numpy.linspace(
            __mdws.getDimension(1).getMinimum(),
            __mdws.getDimension(1).getMaximum(), intensity.shape[1])
        Y, X = numpy.meshgrid(y, x)
        xx, yy = self.tr(X, Y)
        Z = numpy.ma.masked_array(intensity, intensity == 0)
        Z = Z[:-1, :-1]
        # plotting
        if self.sender() is self.plotButton or self.needToClear:
            self.figure.clear()
            self.trajfig.clear()
            self.figure.add_subplot(self.trajfig)
            self.needToClear = False
        self.trajfig.pcolorfast(xx, yy, Z)

        if self.aspectButton.isChecked():
            self.trajfig.set_aspect(1.)
        else:
            self.trajfig.set_aspect('auto')
        self.trajfig.set_xlabel(self.masterDict['dimNames'][0])
        self.trajfig.set_ylabel(self.masterDict['dimNames'][1])
        self.trajfig.grid(True)
        self.canvas.draw()
        mantid.simpleapi.DeleteWorkspace(__mdws)

    def save(self):
        fileName = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save Plot', self.saveDir, '*.png')
        if isinstance(fileName, tuple):
            fileName = fileName[0]
        if not fileName:
            return
        data = "Instrument " + self.masterDict['instrument'] + '\n'
        if self.masterDict['instrument'] == 'HYSPEC':
            data += "S2 = " + str(self.masterDict['S2']) + '\n'
        data += "Ei = " + str(self.masterDict['Ei']) + ' meV\n'
        data += "Goniometer values:\n"
        gonioAxis0values = numpy.arange(
            self.masterDict['gonioMinvals'][0],
            self.masterDict['gonioMaxvals'][0] +
            0.1 * self.masterDict['gonioSteps'][0],
            self.masterDict['gonioSteps'][0])
        gonioAxis1values = numpy.arange(
            self.masterDict['gonioMinvals'][1],
            self.masterDict['gonioMaxvals'][1] +
            0.1 * self.masterDict['gonioSteps'][1],
            self.masterDict['gonioSteps'][1])
        gonioAxis2values = numpy.arange(
            self.masterDict['gonioMinvals'][2],
            self.masterDict['gonioMaxvals'][2] +
            0.1 * self.masterDict['gonioSteps'][2],
            self.masterDict['gonioSteps'][2])
        for g0 in gonioAxis0values:
            for g1 in gonioAxis1values:
                for g2 in gonioAxis2values:
                    data += "    " + self.masterDict['gonioLabels'][
                        0] + " = " + str(g0)
                    data += "    " + self.masterDict['gonioLabels'][
                        1] + " = " + str(g1)
                    data += "    " + self.masterDict['gonioLabels'][
                        2] + " = " + str(g2) + '\n'
        data += "Lattice parameters:\n"
        data += "    a = " + str(self.ol.a()) + "    b = " + str(
            self.ol.b()) + "    c = " + str(self.ol.c()) + '\n'
        data += "    alpha = " + str(self.ol.alpha()) + "    beta = " + str(
            self.ol.beta()) + "    gamma = " + str(self.ol.gamma()) + '\n'
        data += "Orientation vectors:\n"
        data += "    u = " + str(self.ol.getuVector()) + '\n'
        data += "    v = " + str(self.ol.getvVector()) + '\n'
        data += "Integrated " + self.masterDict['dimNames'][2] + " between " + \
                str(self.masterDict['dimMin'][2]) + " and " + str(self.masterDict['dimMax'][2]) + '\n'
        data += "Integrated " + self.masterDict['dimNames'][3] + " between " + \
                str(self.masterDict['dimMin'][3]) + " and " + str(self.masterDict['dimMax'][3]) + '\n'

        info = self.figure.text(0.2, 0, data, verticalalignment='top')
        self.figure.savefig(fileName,
                            bbox_inches='tight',
                            additional_artists=info)
        self.saveDir = os.path.dirname(fileName)

    def tr(self, x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        # one of the axes is energy
        if self.masterDict['dimIndex'][0] == 3 or self.masterDict['dimIndex'][
                1] == 3:
            return x, y
        else:
            h1, k1, l1 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][0]].split(','))
            h2, k2, l2 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][1]].split(','))
            angle = numpy.radians(self.ol.recAngle(h1, k1, l1, h2, k2, l2))
            return 1. * x + numpy.cos(angle) * y, numpy.sin(angle) * y

    def inv_tr(self, x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        # one of the axes is energy
        if self.masterDict['dimIndex'][0] == 3 or self.masterDict['dimIndex'][
                1] == 3:
            return x, y
        else:
            h1, k1, l1 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][0]].split(','))
            h2, k2, l2 = (float(temp) for temp in self.masterDict['dimBasis'][
                self.masterDict['dimIndex'][1]].split(','))
            angle = numpy.radians(self.ol.recAngle(h1, k1, l1, h2, k2, l2))
            return 1. * x - y / numpy.tan(angle), y / numpy.sin(angle)
Exemple #38
0
def plotSpikeCountDistributions(sessions,groups=None,sessionTypes=None,samplingRate=30000.0,save=False,windowSize=40,fname=None,figsize=(10,6)):
    """Plots the isi distributions for all the cells in the given sessions"""
    fig = plt.figure(figsize=figsize)
    fig.subplots_adjust(left=0.05,right=.95)
    spikeCounts = {}
    ncells = 0
    nz = {}
    if sessionTypes != None:
        sessionTypes = dict(zip(sessions,sessionTypes))
    for g in groups:
        for s in sessions:
            dataFile = h5py.File(os.path.expanduser('~/Documents/research/data/spikesorting/hmm/p=1e-20/%sg%.4d.hdf5' % (s,g)),'r')
            try:
                for c in dataFile['unitTimePoints'].keys():
                    sptrain = dataFile['unitTimePoints'][c][:]/(samplingRate/1000)
                    nbins = sptrain.max()/windowSize
                    bins,bs = np.linspace(0,sptrain.max(),nbins,retstep=True)
                    sc,bins = np.histogram(sptrain,bins)
                    cn = 'g%dc%d' % (g,int(c))
                    sl = s
                    if sessionTypes != None:
                        sl = sessionTypes[s]
                    if cn in spikeCounts:
                        spikeCounts[cn]['%s' %(s,)] = {'counts': sc, 'bins':bins}
                        nz[cn]['%s' %( sl,)] = 1.0*sum(sc==0)/len(sc)
                    else:
                        spikeCounts[cn] = {'%s' %(s,):  {'counts':sc,'bins':bins}}
                        nz[cn] = {'%s' %(sl,): 1.0*sum(sc==0)/len(sc)}
            finally:
                dataFile.close()
        
    i = 1
    ncells = len(spikeCounts.keys())
    nsessions = len(sessions)
    colors = ['b','r','g','y','c','m']
    for c in spikeCounts.keys():
        ax = Subplot(fig,1,ncells,i)
        formatAxis(ax)
        fig.add_axes(ax)
        ax.set_title(c)
        j = 0
        for k,v in spikeCounts[c].items():
            #n,b = np.histogram(v['counts'],bins=20,normed=True)
            #plt.plot(b[:-1],n,label=k)
            if sessionTypes != None:
                L = sessionTypes[k]
            else:
                L = k
            n = np.bincount(v['counts'])
            b = np.unique(v['counts'])
            b = np.arange(b[0],len(n))
            ax.bar(b+j*0.2,1.0*n/n.sum(),align='center',width=0.3,fc=colors[j],label=L)
            j+=1
        i+=1
        ax.set_xlabel('Spike counts')
    fig.axes[-1].legend()
    if save:
        if fname == None:
            fname = os.path.expanduser('~/Documents/research/figures/isi_comparison.pdf')
        fig.savefig(fname,bbox='tight')

    return nz
Exemple #39
0
]
x_mixing_ratios = [
    x_from_Tp((Bolton.mixing_ratio_line(p_all, MRi) + C_to_K), p_all)
    for MRi in mixing_ratios
]
mesh_T, mesh_p = np.meshgrid(
    np.arange(-60.0,
              T_levels.max() - C_to_K + 0.1, 0.1), p_all)
theta_ep_mesh = Bolton.theta_ep_field(mesh_T, mesh_p)

# Plotting Code!

skew_grid_helper = GridHelperCurveLinear((from_thermo, to_thermo))

fig = plt.figure()
ax = Subplot(fig, 1, 1, 1, grid_helper=skew_grid_helper)
fig.add_subplot(ax)

for yi in y_p_levels:
    ax.plot((x_min, x_max), (yi, yi), color=(1.0, 0.8, 0.8))

for x_T in x_T_levels:
    ax.plot(x_T, y_all_p, color=(1.0, 0.5, 0.5))

for x_theta in x_thetas:
    ax.plot(x_theta, y_all_p, color=(1.0, 0.7, 0.7))

for x_mixing_ratio in x_mixing_ratios:
    good = p_all >= 600  # restrict mixing ratio lines to below 600 mb
    ax.plot(x_mixing_ratio[good], y_all_p[good], color=(0.8, 0.8, 0.6))
Exemple #40
0
def plotwitherrors(time, timeunit, means, meansunit, std):
    # ---> basic settings
    title = input('Title: ')
    y_name = input('Observable name: ')
    if title == '' or y_name == '':
        title = 'test'
        y_name = 'test'

    axistop_bool = False
    axisright_bool = False
    axisbottom_bool = True
    axisleft_bool = True
    # <--- basic settings

    # ---> analyse data
    # <--- analyse data

    # plot --->
    fig = plt.figure()
    ax = Subplot(fig, 111)
    fig.add_subplot(ax)

    ax.errorbar(time,
                means,
                yerr=std,
                marker='o',
                markersize=2,
                c='black',
                linestyle='none',
                ecolor='black',
                elinewidth=1,
                capthick=1,
                capsize=3)

    ax.plot(time,
            means,
            color='black',
            alpha=0.5,
            linewidth=1.0,
            linestyle='--')

    #legend and labels
    ax.legend(loc='best')
    plt.xlabel('time in ' + timeunit, **hfont)
    plt.ylabel(y_name + ' in ' + meansunit, **hfont)

    # visible axis
    ax.axis["right"].set_visible(axisright_bool)
    ax.axis["top"].set_visible(axistop_bool)
    ax.axis["bottom"].set_visible(axisbottom_bool)
    ax.axis["left"].set_visible(axisleft_bool)

    # <--- plot

    # save plot --->
    pdfdirectory = '../../figures/' + title + '.pdf'
    pgfdirectory = '../../figures/' + title + '.pgf'
    fig.savefig(pdfdirectory)
    plt.savefig(pgfdirectory)
    # <--- save plot

    print('test run successful')
    return None
Exemple #41
0
    def __init__(self, ol=None, parent=None):
        # pylint: disable=unused-argument,super-on-old-class
        super(DGSPlannerGUI, self).__init__(parent)
        #OrientedLattice
        if ValidateOL(ol):
            self.ol = ol
        else:
            self.ol = mantid.geometry.OrientedLattice()
        self.masterDict = dict()  #holds info about instrument and ranges
        self.updatedInstrument = False
        self.updatedOL = False
        self.wg = None  #workspace group
        self.instrumentWidget = InstrumentSetupWidget.InstrumentSetupWidget(
            self)
        self.setLayout(QtGui.QHBoxLayout())
        controlLayout = QtGui.QVBoxLayout()
        controlLayout.addWidget(self.instrumentWidget)
        self.ublayout = QtGui.QHBoxLayout()
        self.classic = ClassicUBInputWidget.ClassicUBInputWidget(self.ol)
        self.ublayout.addWidget(self.classic,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        self.matrix = MatrixUBInputWidget.MatrixUBInputWidget(self.ol)
        self.ublayout.addWidget(self.matrix,
                                alignment=QtCore.Qt.AlignTop,
                                stretch=1)
        controlLayout.addLayout(self.ublayout)
        self.dimensionWidget = DimensionSelectorWidget.DimensionSelectorWidget(
            self)
        controlLayout.addWidget(self.dimensionWidget)
        plotControlLayout = QtGui.QGridLayout()
        self.plotButton = QtGui.QPushButton("Plot", self)
        self.oplotButton = QtGui.QPushButton("Overplot", self)
        self.helpButton = QtGui.QPushButton("?", self)
        self.colorLabel = QtGui.QLabel('Color by angle', self)
        self.colorButton = QtGui.QCheckBox(self)
        self.colorButton.toggle()
        self.aspectLabel = QtGui.QLabel('Aspect ratio 1:1', self)
        self.aspectButton = QtGui.QCheckBox(self)
        self.saveButton = QtGui.QPushButton("Save Figure", self)
        plotControlLayout.addWidget(self.plotButton, 0, 0)
        plotControlLayout.addWidget(self.oplotButton, 0, 1)
        plotControlLayout.addWidget(self.colorLabel, 0, 2,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.colorButton, 0, 3)
        plotControlLayout.addWidget(self.aspectLabel, 0, 4,
                                    QtCore.Qt.AlignRight)
        plotControlLayout.addWidget(self.aspectButton, 0, 5)
        plotControlLayout.addWidget(self.helpButton, 0, 6)
        plotControlLayout.addWidget(self.saveButton, 0, 7)
        controlLayout.addLayout(plotControlLayout)
        self.layout().addLayout(controlLayout)

        #figure
        self.figure = Figure()
        self.figure.patch.set_facecolor('white')
        self.canvas = FigureCanvas(self.figure)
        self.grid_helper = GridHelperCurveLinear((self.tr, self.inv_tr))
        self.trajfig = Subplot(self.figure,
                               1,
                               1,
                               1,
                               grid_helper=self.grid_helper)
        self.trajfig.hold(True)
        self.figure.add_subplot(self.trajfig)
        self.layout().addWidget(self.canvas)
        self.needToClear = False
        self.saveDir = ''

        #connections
        self.matrix.UBmodel.changed.connect(self.updateUB)
        self.matrix.UBmodel.changed.connect(self.classic.updateOL)
        self.classic.changed.connect(self.matrix.UBmodel.updateOL)
        self.classic.changed.connect(self.updateUB)
        self.instrumentWidget.changed.connect(self.updateParams)
        self.dimensionWidget.changed.connect(self.updateParams)
        self.plotButton.clicked.connect(self.updateFigure)
        self.oplotButton.clicked.connect(self.updateFigure)
        self.helpButton.clicked.connect(self.help)
        self.saveButton.clicked.connect(self.save)
        #force an update of values
        self.instrumentWidget.updateAll()
        self.dimensionWidget.updateChanges()
        #help
        self.assistantProcess = QtCore.QProcess(self)
        # pylint: disable=protected-access
        self.collectionFile = os.path.join(mantid._bindir,
                                           '../docs/qthelp/MantidProject.qhc')
        version = ".".join(mantid.__version__.split(".")[:2])
        self.qtUrl = 'qthelp://org.sphinx.mantidproject.' + version + '/doc/interfaces/DGSPlanner.html'
        self.externalUrl = 'http://docs.mantidproject.org/nightly/interfaces/DGSPlanner.html'
        #control for cancel button
        self.iterations = 0
        self.progress_canceled = False
Exemple #42
0
    def __init__(
        self,
        figure=None,
        isotherm_locator=None,
        dry_adiabat_locator=None,
        anchor=None,
    ):
        """
        Initialise the tephigram transformation and plot axes.

        Kwargs:

        * figure:
            An existing :class:`matplotlib.figure.Figure` instance for the
            tephigram plot. If a figure is not provided, a new figure will
            be created by default.
        * isotherm_locator:
            A :class:`tephi.Locator` instance or a numeric step size
            for the isotherm lines.
        * dry_adiabat_locator:
            A :class:`tephi.Locator` instance or a numeric step size
            for the dry adiabat lines.
        * anchor:
            A sequence of two pressure, temperature pairs specifying the extent
            of the tephigram plot in terms of the bottom left hand corner and
            the top right hand corner. Pressure data points must be in units of
            mb or hPa, and temperature data points must be in units of degC.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from numpy import column_stack
            import os.path
            import tephi
            from tephi import Tephigram

            dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt')
            dry_bulb = os.path.join(tephi.DATA_DIR, 'temps.txt')
            dew_data, temp_data = tephi.loadtxt(dew_point, dry_bulb)
            dews = column_stack((dew_data.pressure, dew_data.temperature))
            temps = column_stack((temp_data.pressure, temp_data.temperature))
            tpg = Tephigram()
            tpg.plot(dews, label='Dew-point', color='blue', linewidth=2)
            tpg.plot(temps, label='Dry-bulb', color='red', linewidth=2)
            plt.show()

        """
        if not figure:
            # Create a default figure.
            self.figure = plt.figure(0, figsize=(9, 9))
        else:
            self.figure = figure

        # Configure the locators.
        if isotherm_locator and not isinstance(isotherm_locator, Locator):
            if not isinstance(isotherm_locator, numbers.Number):
                raise ValueError("Invalid isotherm locator")
            locator_isotherm = Locator(isotherm_locator)
        else:
            locator_isotherm = isotherm_locator

        if dry_adiabat_locator and not isinstance(dry_adiabat_locator,
                                                  Locator):
            if not isinstance(dry_adiabat_locator, numbers.Number):
                raise ValueError("Invalid dry adiabat locator")
            locator_theta = Locator(dry_adiabat_locator)
        else:
            locator_theta = dry_adiabat_locator

        # Define the tephigram coordinate-system transformation.
        self.tephi_transform = transforms.TephiTransform()
        ghelper = GridHelperCurveLinear(
            self.tephi_transform,
            tick_formatter1=_FormatterIsotherm(),
            grid_locator1=locator_isotherm,
            tick_formatter2=_FormatterTheta(),
            grid_locator2=locator_theta,
        )
        self.axes = Subplot(self.figure, 1, 1, 1, grid_helper=ghelper)
        self.transform = self.tephi_transform + self.axes.transData
        self.axes.axis["isotherm"] = self.axes.new_floating_axis(1, 0)
        self.axes.axis["theta"] = self.axes.new_floating_axis(0, 0)
        self.axes.axis["left"].get_helper().nth_coord_ticks = 0
        self.axes.axis["left"].toggle(all=True)
        self.axes.axis["bottom"].get_helper().nth_coord_ticks = 1
        self.axes.axis["bottom"].toggle(all=True)
        self.axes.axis["top"].get_helper().nth_coord_ticks = 0
        self.axes.axis["top"].toggle(all=False)
        self.axes.axis["right"].get_helper().nth_coord_ticks = 1
        self.axes.axis["right"].toggle(all=True)
        self.axes.gridlines.set_linestyle("solid")

        self.figure.add_subplot(self.axes)

        # Configure default axes.
        axis = self.axes.axis["left"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("baseline")
        axis.major_ticklabels.set_rotation(135)
        axis = self.axes.axis["right"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("baseline")
        axis.major_ticklabels.set_rotation(-135)
        self.axes.axis["top"].major_ticklabels.set_fontsize(10)
        axis = self.axes.axis["bottom"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_ha("left")
        axis.major_ticklabels.set_va("top")
        axis.major_ticklabels.set_rotation(-45)

        # Isotherms: lines of constant temperature (degC).
        axis = self.axes.axis["isotherm"]
        axis.set_axis_direction("right")
        axis.set_axislabel_direction("-")
        axis.major_ticklabels.set_rotation(90)
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("bottom")
        axis.major_ticklabels.set_color("grey")
        axis.major_ticklabels.set_visible(False)  # turned-off

        # Dry adiabats: lines of constant potential temperature (degC).
        axis = self.axes.axis["theta"]
        axis.set_axis_direction("right")
        axis.set_axislabel_direction("+")
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("bottom")
        axis.major_ticklabels.set_color("grey")
        axis.major_ticklabels.set_visible(False)  # turned-off
        axis.line.set_linewidth(3)
        axis.line.set_linestyle("--")

        # Lock down the aspect ratio.
        self.axes.set_aspect(1.0)
        self.axes.grid(True)

        # Initialise the text formatter for the navigation status bar.
        self.axes.format_coord = self._status_bar

        # Factor in the tephigram transform.
        ISOBAR_TEXT["transform"] = self.transform
        WET_ADIABAT_TEXT["transform"] = self.transform
        MIXING_RATIO_TEXT["transform"] = self.transform

        # Create plot collections for the tephigram isopleths.
        func = partial(
            isopleths.isobar,
            MIN_THETA,
            MAX_THETA,
            self.axes,
            self.transform,
            ISOBAR_LINE,
        )
        self._isobars = _PlotCollection(
            self.axes,
            ISOBAR_SPEC,
            MAX_PRESSURE,
            func,
            ISOBAR_TEXT,
            fixed=ISOBAR_FIXED,
            minimum=MIN_PRESSURE,
        )

        func = partial(
            isopleths.wet_adiabat,
            MAX_PRESSURE,
            MIN_TEMPERATURE,
            self.axes,
            self.transform,
            WET_ADIABAT_LINE,
        )
        self._wet_adiabats = _PlotCollection(
            self.axes,
            WET_ADIABAT_SPEC,
            MAX_WET_ADIABAT,
            func,
            WET_ADIABAT_TEXT,
            fixed=WET_ADIABAT_FIXED,
            minimum=MIN_WET_ADIABAT,
            xfocus=True,
        )

        func = partial(
            isopleths.mixing_ratio,
            MIN_PRESSURE,
            MAX_PRESSURE,
            self.axes,
            self.transform,
            MIXING_RATIO_LINE,
        )
        self._mixing_ratios = _PlotCollection(
            self.axes,
            MIXING_RATIO_SPEC,
            MIXING_RATIOS,
            func,
            MIXING_RATIO_TEXT,
            fixed=MIXING_RATIO_FIXED,
        )

        # Initialise for the tephigram plot event handler.
        plt.connect("motion_notify_event", _handler)
        self.axes.tephigram = True
        self.axes.tephigram_original_delta_xlim = DEFAULT_WIDTH
        self.original_delta_xlim = DEFAULT_WIDTH
        self.axes.tephigram_transform = self.tephi_transform
        self.axes.tephigram_inverse = self.tephi_transform.inverted()
        self.axes.tephigram_isopleths = [
            self._isobars,
            self._wet_adiabats,
            self._mixing_ratios,
        ]

        # The tephigram profiles.
        self._profiles = []
        self.axes.tephigram_profiles = self._profiles

        # Center the plot around the anchor extent.
        self._anchor = anchor
        if self._anchor is not None:
            self._anchor = np.asarray(anchor)
            if (self._anchor.ndim != 2 or self._anchor.shape[-1] != 2
                    or len(self._anchor) != 2):
                msg = ("Invalid anchor, expecting [(bottom-left-pressure, "
                       "bottom-left-temperature), (top-right-pressure, "
                       "top-right-temperature)]")
                raise ValueError(msg)
            (
                (bottom_pressure, bottom_temp),
                (top_pressure, top_temp),
            ) = self._anchor

            if (bottom_pressure - top_pressure) < 0:
                raise ValueError("Invalid anchor pressure range")
            if (bottom_temp - top_temp) < 0:
                raise ValueError("Invalid anchor temperature range")

            self._anchor = isopleths.Profile(anchor, self.axes)
            self._anchor.plot(visible=False)
            xlim, ylim = self._calculate_extents()
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)