Example #1
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)
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)
def plotCorrelation(tauArray,kappaMatrix,kappaLower=None,kappaUpper=None,CI=None,amplify=1):
    
    """Plots Pearson Correlation Coefficient K(t,tau) with rotated
    axis to indicate absolute t, and relative time shift tau, between
    two signals x(t),y(t).
    
    Specified matrix has to be square with values -1 < p < +1
    with corresponding time array giving the absolute time, t
    of the centers of each correlated window."""

    # defining tranformation for relative time shifts
    def R(x, y):
        x, y = asarray(x), asarray(y)
        #return x,y
        return (2*x - y)/2, (y + 2*x)/2

    def Rt(x, y):
        x, y = asarray(x), asarray(y)
        #return x,y
        return x + y, x - y

    # create figure with rotated axes
    fig = figure(figsize=(10, 10),frameon=False)
    grid_locator = angle_helper.LocatorDMS(20)
    grid_helper = GridHelperCurveLinear((R, Rt),
                  grid_locator1=grid_locator,
                  grid_locator2=grid_locator)
    
    ax = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
    fig.add_subplot(ax);ax.axis('off');
    
    # copying over matrix
    K = array(kappaMatrix)
    
    # zero out correlations if confidence intervals overlap zero
    if all(kappaLower != None) and all(kappaUpper != None) :
        K[ (kappaLower<0) * (0<kappaUpper) ] = 0
        
    # zero out statistically insignificant correlations
    if all(CI != None) :
        K[ abs(kappaMatrix) < CI ] = 0
    
    # display pearson correlation matrix with +ive in red and -ive in blue
    ax.imshow(K,cmap="RdBu_r",interpolation="none",origin="bottom",
              extent = (tauArray[0],tauArray[-1],tauArray[0],tauArray[-1]),vmin=-1.0/amplify,vmax=1.0/amplify)

    # display rotated axes time,t and time delay,tau
    ax.axis["tau"] = tau = ax.new_floating_axis(0,0)
    ax.axis["t"] = t = ax.new_floating_axis(1,0)
    
    # setting axes options
    ax.set_xlim(tauArray[0],tauArray[-1])
    ax.set_ylim(tauArray[0],tauArray[-1])
    ax.grid(which="both")
    ax.set_aspect(1)
    
    return fig
Example #4
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
Example #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
Example #6
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)
Example #7
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)
Example #8
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)
Example #9
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)
Example #10
0
    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()
Example #11
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)
Example #12
0
                        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)
        #ax2.axis['right'].label.set_text(r'Number of Tiles')
        ax2.axis['left'].label.set_text(r'PDF')
        ax2.axis['bottom'].label.set_visible(True)
        ax2.axis['bottom'].label.set_text(
            r'Surface Brightness Limit (mag arcsec$^{-2}$)')
        if band == 'z':
            ax2.set_aspect(1.5)
        elif band == 'Y':
            ax2.set_aspect(1.2)
        else:
            ax2.set_aspect(0.8)

        #forceAspect(ax2,aspect=1)
        #plt.suptitle(f'{band}-band ({size}" x {size}")',y=0.92)

        plt.legend(loc='upper left')

        outfile = f'sbcontrast_{band}_s{size:d}_v2.pdf'
        print(f"  {outfile}")
        plt.savefig(outfile, bbox_inches='tight')

        #outfile = outfile.replace('.pdf','.png')
Example #13
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])
Example #14
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])