Ejemplo n.º 1
0
    def _removeButtonClicked(self):
        """
      Remove the active component.
    """
        if self._compoCount < 2:
            return

        # Create new model
        if self._mode == "voigt":
            nm = fuf.MultiVoigt1d(self._compoCount - 1)
        else:
            nm = fuf.MultiGauss1d(self._compoCount - 1)

        # The offset has to be treated separately
        nm["off"] = self._model["off"]
        if "off" in self._model.freeParamNames():
            nm.thaw("off")

        # t counts the "target" component
        t = 0
        for i in smo.range(1, self._compoCount + 1):
            if i == self._activeComponent:
                # Disregard the currently active component
                continue
            n = str(i)
            t += 1
            for p in self._compPars:
                nm[p + str(t)] = self._model[p + n]
                if (p + n) in self._model.freeParamNames():
                    nm.thaw(p + str(t))

        self._model = nm
        self._compoCount -= 1
        self._downAC()
        self._updateGUI()
Ejemplo n.º 2
0
 def __init__(self, lineList, uniSig=None, modelBinsize=0.005, useFastRB=True, verbose=False, onlyAbs=True):
   
   if not ic.check["scipy"]:
     raise(PE.PyARequiredImport("Could not import scipy.", \
                                solution="Install scipy."))
   # Check whether depths are given
   self._depthsGiven = (len(lineList[0,::]) == 3)
   if (not self._depthsGiven) and (uniSig is None):
     raise(PE.PyAValError("No width and no depth given.", \
                          solution="Specify line depth in `lineList` or use `uniSig`."))
   # Check whether unified sigma shall be used
   # Note: Line depth will be ignored then
   self._uniSig = uniSig 
   
   # Only absorption lines
   self._onlyAbs = onlyAbs
   # Verbosity
   self._verbose = verbose
   # Use fast rotational broadening?
   self._usefastRB = useFastRB
   # Save binsize for the model
   self._modelBinsize = modelBinsize
   # Copy line list
   self._lineList = lineList.copy()
   # Number of lines
   self._nl = len(lineList[::,0])
   # A MultiGaussFit object
   self._mg = fuf.MultiGauss1d(self._nl)
   # Store all parameter names from GaussFit
   pars = list(self._mg.parameters().keys())
   # Remove lin and off from multiGauss keys
   pars.remove("lin")
   pars.remove("off")
   
   pars.extend(["lineScale", "scale", "eps", "vrad", "vsini"])
   fuf.OneDFit.__init__(self, pars)
   # Name the model
   self.setRootName("LineListGauss")
   
   # Assign start values
   for i in range(self._nl):
     p = str(i+1)
     # Assign position
     self._mg["mu"+p] = lineList[i,0]
     self["mu"+p] = lineList[i,0]
     # Assign amplitude/EW
     # Note: Positive EWs correspond to absorption lines
     self._mg["A"+p] = -lineList[i,1]
     self["A"+p] = lineList[i,1]
     # Assign width (sigma)
     if self._depthsGiven and (self._uniSig is None):
       # Depth IS given and no unified sigma specified
       self._mg["sig"+p] = abs(lineList[i,1])/((1.-lineList[i,2]) * np.sqrt(2.*np.pi))
       self["sig"+p] = self._mg["sig"+p] 
     elif not (self._uniSig is None):
       # uniSig IS given
       self._mg["sig"+p] = self._uniSig
       self["sig"+p] = self._mg["sig"+p] 
   
   self["scale"] = 1.0
   self["lineScale"] = 1.0
   
   if self._onlyAbs:
     # Apply restrictions to prevent emission lines
     for i in range(self._nl):
       p = str(i+1)
       self.setRestriction({"A"+p:[0.0, None]})
Ejemplo n.º 3
0
    def _newCompAddPoint(self, event):
        """
      Add a point to point cache or create component if point set is complete.
    """
        p = Point(event)
        # Plot point on canvas
        self.a.plot([p.xdata], [p.ydata], 'r+', markersize=10)
        self._pointCache.append([p, self.a.lines[-1]])

        if len(self._pointCache) < 3:
            # More points have to be added
            self._updateView()
            return

        # Three points have been added
        fwhm = np.abs(self._pointCache[0][0].xdata -
                      self._pointCache[2][0].xdata)
        depth = self._model["off"] - self._pointCache[1][0].ydata
        # Estimate std (Gaussian)
        sigma = fwhm / 2.35482
        # Estimate area of a Gaussian with given depth
        agauss = sigma * np.sqrt(2. * np.pi) * depth

        # Add further component
        self._compoCount += 1
        if self._mode == "voigt":
            nmodel = fuf.MultiVoigt1d(self._compoCount)
        elif self._mode == "gauss":
            nmodel = fuf.MultiGauss1d(self._compoCount)
        # Assign parameters from old model
        nmodel.assignValues(self._model.parameters())
        # Transfer free parameters
        nmodel.thaw(self._model.freeParamNames())
        self._model = nmodel

        if self._mode == "voigt":
            c0 = 2.0056
            c1 = 1.0593
            # fl/fg
            phi = self._config["default_alad"]
            fg = fwhm / (1.0 - c0 * c1 +
                         np.sqrt(phi**2 + 2. * c1 * phi + c0**2 * c1**2))
            fl = phi * fg
            n = str(self._compoCount)
            self._model["A" + n] = -agauss
            self._model["al" + n] = fl / 2.0
            self._model["ad" + n] = fg / (2. * (2. * np.log(2.0)))
            self._model["mu" + n] = self._pointCache[1][0].xdata
            # Thaw default parameters
            self._model.thaw([x + n for x in self._config["defaultFreeVoigt"]])
        elif self._mode == "gauss":
            n = str(self._compoCount)
            self._model["A" + n] = -agauss
            self._model["sig" + n] = sigma
            self._model["mu" + n] = self._pointCache[1][0].xdata
            # Thaw default parameters
            self._model.thaw([x + n for x in self._config["defaultFreeGauss"]])
            if (self._commonSig.get() == 1) and (self._compoCount > 1):
                # Common widths for Gaussians requested
                self._model.thaw("sig" + n)
                self._model.relate("sig" + n, ["sig" + str(1)])

        self._cleanPointCache()
        self._updateGUI()
Ejemplo n.º 4
0
    def __init__(self, x, y, yerr=None, mode="gauss", config=None):
        self.windowTitle = "PyA interactive GV"
        self.f = Figure()
        self.a = self.f.add_subplot(111)

        self._config = {"modelLS":'r--', \
                        "dataLS":'bp', \
                        "dataLSerr":'b+', \
                        "activeCompLS":'k-', \
                        "inactiveCompLS":'y--', \
                        "plotIndComps":True, \
                        "rangeLS":'m--', \
                        "defaultFreeVoigt":["A", "ad", "al", "mu"], \
                        "default_alad":0.1, \
                        "defaultFreeGauss":["A", "sig", "mu"], \
                        "defaultWheelAdd":0.01, \
                        "defaultWheelMult": 2}

        # Modify configuration according to input
        if config is not None:
            for k in six.iterkeys(self._config):
                if k in config:
                    # Value has been modified
                    self._config[k] = config[k]

        # Tk root
        self.root = tk.Tk()

        # Create data plot
        self._x = x
        self._y = y
        self._yerr = yerr
        if self._yerr is None:
            self.a.plot(x, y, self._config["dataLS"])
        else:
            self.a.errorbar(x,
                            y,
                            yerr=self._yerr,
                            fmt=self._config["dataLSerr"])

        # The input mode determines how clicks on the mouse wheel are
        # interpreted.
        self._inputMode = "newComp"

        # Component count/assignment starts at 1
        self._activeComponent = 1
        self._compoCount = 0

        # Create model and parameter lists
        self._mode = mode
        if self._mode == "voigt":
            self._model = fuf.MultiVoigt1d(1)
            self._compPars = ["mu", "ad", "al", "A"]
        elif self._mode == "gauss":
            self._model = fuf.MultiGauss1d(1)
            self._compPars = ["mu", "sig", "A"]
        else:
            raise(PE.PyAValError("No such mode: " + str(self._mode), \
                                 solution="Choose either 'voigt' or 'gauss'."))
        self._model["off"] = 1.0

        # List used to cache points used to add component
        # as long as component is not completely specified
        self._pointCache = []

        # What to consider in the fit
        self._rangeIndices = np.arange(self._x.size, dtype=np.int)

        # A frame containing the mpl plot
        self.plotFrame = tk.Frame()
        self.plotFrame.pack(fill=tk.BOTH, side=tk.LEFT, expand=True)
        self.canvas = FigureCanvasTkAgg(self.f, master=self.plotFrame)

        # A frame containing the box with selected points
        # and control buttons
        self.pointFrame = tk.Frame(self.root)
        self.pointFrame.pack(side=tk.LEFT, fill=tk.BOTH)

        # Manage active component
        self.activeCompoFrame = tk.Frame(self.pointFrame)
        self.activeCompoFrame.pack(side=tk.TOP)
        self.currentComponentLabel = tk.Label(self.activeCompoFrame,
                                              text="Active component")
        self.currentComponentLabel.pack(side=tk.TOP)
        # De- and increase no. of active component
        self.downACB = tk.Button(self.activeCompoFrame,
                                 text="-",
                                 command=self._downAC)
        self._acstring = tk.StringVar()
        self._acstring.set(str(self._activeComponent))
        self.ACLabel = tk.Label(self.activeCompoFrame,
                                textvariable=self._acstring)
        self.upACB = tk.Button(self.activeCompoFrame,
                               text="+",
                               command=self._upAC)
        self.downACB.pack(side=tk.LEFT)
        self.ACLabel.pack(side=tk.LEFT)
        self.upACB.pack(side=tk.RIGHT)

        # Show and work with parameters
        self.parameterFrame = tk.Frame(self.pointFrame,
                                       relief=tk.RAISED,
                                       borderwidth=1)
        self.parameterFrame.pack(side=tk.TOP)
        # Headline
        tk.Label(self.parameterFrame,
                 text="Parameters (active comp.)").pack(side=tk.TOP)
        # List of parameters to show
        pars = ["off"]
        pars.extend(self._compPars)
        self._parSelect = tk.IntVar()
        # Frames for individual parameters
        self._parFrames = []
        self._parValues = []
        self._parFreeVars = []

        for i, p in enumerate(pars):
            self._parFrames.append(tk.Frame(self.parameterFrame))
            self._parFrames[-1].pack(side=tk.TOP)
            b = tk.Radiobutton(self._parFrames[-1],
                               text="",
                               variable=self._parSelect,
                               value=i)
            b.pack(side=tk.LEFT, anchor=tk.W)
            l = tk.Label(self._parFrames[-1], text=("%3s" % p), width=3)
            l.pack(side=tk.LEFT, anchor=tk.W)
            self._parValues.append(tk.StringVar())
            self._parValues[-1].set("0.0")
            l = tk.Label(self._parFrames[-1],
                         textvariable=self._parValues[-1],
                         width=10)
            l.pack(side=tk.LEFT)

            self._parFreeVars.append(tk.IntVar())
            c = tk.Checkbutton(self._parFrames[-1], text="free", variable=self._parFreeVars[-1], \
                               command=self._freeCheckboxClicked)
            c.pack(side=tk.LEFT)

        # Wheel modification
        self._wheelModFrame = tk.Frame(self.pointFrame,
                                       relief=tk.RAISED,
                                       borderwidth=1)
        self._wheelModFrame.pack(side=tk.TOP)
        # Headline
        tk.Label(self._wheelModFrame, text="Mouse wheel").pack(side=tk.TOP)
        self._multAddSelect = tk.IntVar()
        self._multAddSelect.set(1)
        multiFrame = tk.Frame(self._wheelModFrame)
        addFrame = tk.Frame(self._wheelModFrame)
        multiFrame.pack(side=tk.TOP)
        addFrame.pack(side=tk.TOP)
        tk.Radiobutton(multiFrame,
                       text="multiply [%]",
                       variable=self._multAddSelect,
                       value=1,
                       width=9,
                       anchor=tk.W).pack(side=tk.LEFT)
        tk.Radiobutton(addFrame,
                       text="add",
                       variable=self._multAddSelect,
                       value=2,
                       width=9,
                       anchor=tk.W).pack(side=tk.LEFT)
        self._multNumber = tk.StringVar()
        self._addNumber = tk.StringVar()
        self._multNumber.set(str(self._config["defaultWheelMult"]))
        self._addNumber.set(str(self._config["defaultWheelAdd"]))
        self._multNumberEntry = tk.Entry(multiFrame,
                                         textvariable=self._multNumber,
                                         width=10)
        self._multNumberEntry.pack(side=tk.RIGHT)
        self._addNumberEntry = tk.Entry(addFrame,
                                        textvariable=self._addNumber,
                                        width=10)
        self._addNumberEntry.pack(side=tk.RIGHT)

        # Common width
        if self._mode == "gauss":
            commonSigFrame = tk.Frame(self.pointFrame)
            commonSigFrame.pack(side=tk.TOP)
            self._commonSig = tk.IntVar()
            c = tk.Checkbutton(commonSigFrame, text="Common width (sig)", variable=self._commonSig, \
                               command=self._commonSigClicked)
            c.pack(side=tk.LEFT)

        # Fit button
        self._fitButton = tk.Button(self.pointFrame,
                                    text="Fit",
                                    command=self._fitModel)
        self._fitButton.pack(side=tk.TOP, fill=tk.X)

        # Range button
        self._rangeButton = tk.Button(self.pointFrame,
                                      text="Set fit range",
                                      command=self._rangeButtonClicked)
        self._rangeButton.pack(side=tk.TOP, fill=tk.X)

        # Remove button
        self.removeButton = tk.Button(master=self.pointFrame, text="Remove component", \
                                      command=self._removeButtonClicked)
        self.removeButton.pack(side=tk.TOP, fill=tk.X)

        # a tk.DrawingArea
        self.canvas.get_tk_widget().pack()
        self.cid = self.f.canvas.mpl_connect('button_press_event',
                                             self._mouseButtonClicked)
        self.mwe = self.f.canvas.mpl_connect('scroll_event', self._mouseWheel)

        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.plotFrame)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

        def _quit():
            # stops main loop
            self.root.quit()
            # this is necessary on Windows to prevent
            # Fatal Python Error: PyEval_RestoreThread: NULL tstate
            self.root.destroy()

        self.quitButton = tk.Button(master=self.pointFrame,
                                    text='Quit',
                                    command=_quit)
        self.quitButton.pack(side=tk.BOTTOM, fill=tk.X)