{"id":19182026,"url":"https://github.com/glentner/slipy","last_synced_at":"2025-05-07T23:08:28.597Z","repository":{"id":27947959,"uuid":"31440625","full_name":"glentner/SLiPy","owner":"glentner","description":"A Spectroscopy and astrophysics Library for Python 3","archived":false,"fork":false,"pushed_at":"2017-11-21T21:16:14.000Z","size":2926,"stargazers_count":19,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-07T23:08:20.530Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://glentner.github.io/slipy","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/glentner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-27T21:48:29.000Z","updated_at":"2025-03-19T15:04:56.000Z","dependencies_parsed_at":"2022-09-12T01:00:38.202Z","dependency_job_id":null,"html_url":"https://github.com/glentner/SLiPy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glentner%2FSLiPy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glentner%2FSLiPy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glentner%2FSLiPy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glentner%2FSLiPy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/glentner","download_url":"https://codeload.github.com/glentner/SLiPy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252968118,"owners_count":21833251,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T10:56:18.191Z","updated_at":"2025-05-07T23:08:28.569Z","avatar_url":"https://github.com/glentner.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [SLiPy](http://glentner.github.io/SLiPy)\n\n#### A Spectroscopy and astrophysics Library for Python 3\n\nThis Python package is an expanding code base for doing computational\nastronomy, particularly spectroscopy. It contains both a *Spectrum* class\nfor handling spectra as objects (with +, -, \\*, /, etc... operations defined)\nand a growing suite of analysis tools.\n\n**Dependencies:**\nPython 3.x,\n[astropy](http://www.astropy.org),\n[matplotlib](http://matplotlib.org),\n[numpy](http://www.numpy.org),\n[scipy](http://www.scipy.org)\n\n[![astropy](http://img.shields.io/badge/powered%20by-AstroPy-orange.svg?style=flat)](http://www.astropy.org/)\n[![GitHub license](http://img.shields.io/badge/license-GPLv3-blue.svg?style=flat)](http://www.gnu.org/copyleft/gpl.html)\n\nQuick note: the subpackage **astrolibpy** was not developed\nby me. It was coded by Sergey Koposov (@segasai) at Cambridge (then at least).\nI found it useful for performing velocity corrections on my spectroscopic\ndata. I've modified several modules such that it can be imported and used in\nPython 3.x. See his README file.\n\n## Contents\n\nSLiPy is split into several components. The principle component is the\nsubpackage **SLiPy** itself, which contains all the relevant\nfunctionality. Further, **Data** is a package I'm working on that will provide\nan API for searching astronomical data archives in a simple way. The other two\nsubpackages **Framework** and **astrolibpy** are of utility to the project but\nnot necessarily intended for export. As stated previously, astrolibpy was not\ndeveloped by me, only modified. I'm not going to document it's usage here. Its\nname is unfortunate for me as it is a bit over done with the convention I was\nalready using, but for consistency I will keep it as it was from the author.\n\nThe following modules are elevated to the package level and are available\nto import:\n\n| SLiPy/ | Functions/Classes |\n|---------|-------------------|\n|[**Spectrum**](#SpectrumLoc)|[WaveVector](#WaveVectorLoc), [Spectrum](#SpectrumLoc), |\n|[**Fits**](#FitsLoc)|[Find](#FindLoc), [RFind](#RFindLoc), [GetData](#GetDataLoc), [Header](#HeaderLoc), [Search](#SearchLoc), [PositionSort](#PositionSortLoc), |\n|[**Simbad**](#SimbadLoc)|[Position](#PositionLoc), [Distance](#DistanceLoc), [Sptype](#SptypeLoc), [IDList](#IDListLoc), |\n|[**Correlate**](#CorrelateLoc)|[XCorr](#XCorrLoc), |\n|[**Telluric**](#TelluricLoc)|[Correct](#CorrectLoc), |\n|[**Velocity**](#VelocityLoc)|[HelioCorrect](#HelioCorrectLoc), [BaryCorrect](#BaryCorrectLoc), [IrafInput](#IrafInputLoc),  |\n|[**Observatory**](#ObservatoryLoc)|[...](#OHPLoc), |\n|[**Plot**](#PlotLoc)|[SPlot](#SPlotLoc), [Iterate](#IterateLoc), |\n|[**Profile**](#ProfileLoc)|[Select](#SelectLoc), [Fit](#FitLoc), [Extract](#ExtractLoc),   |\n|[**Montage**](#MontageLoc)|[SolveGrid](#MSolveGridLoc), [Mosaic](#MMosaicLoc), [SubField](#MSubFieldLoc), [Field](#MFieldLoc), |\n\n\u003cbr\u003e\n\n| SLiPy/Data | Functions/Classes |\n|------------|-------------------|\n|[**Elodie**](#ElodieLoc)|[Archive](#EArchiveLoc), [Script](#EScriptLoc), [Download](#EDownloadLoc), |\n|[**Atomic**](#AtomicLoc)|[Ion](#IonLoc), [IonManager](#IonManagerLoc), |\n\n## Installation\n\nTo install SLiPy, there is no setup procedure. Simply download the package,\neither by clicking on the download link for a *tar* or *zip* archive or by\ncloning it.\n\nExtract it's contents to wherever you like in a directory (ostensibly named\n*slipy*, but actually you can call this library whatever you want as well\nbecause all the imports are *relative*). Then add the parent directory to your\n*PYTHONPATH* if it isn't already. For example:\n\n```\n$ cd\n$ git clone http://github.com/glentner/slipy\n$ echo \"export PYTHONPATH=$PYTHONPATH:~\" \u003e\u003e ~/.bashrc\n```\n\nAnd your ready to go!\n\n## Exceptions\n\nSLiPy attempts to catch all foreseeable exceptions and re-throw them under a\ncommon handle with a human readable message. There is a unique exception class\nfor every module, all derived from a common *SlipyError*. The naming convention\nis for a module's exception to be named after the module with the addition of\nthe word *Error*. So the *Fits* module will throw a *FitsError*. These are meant\nto handle erros internally. The user need not worry about these in an\ninteractive session; however, inside of scipts you might catch *SlipyError*.\nFor finer control, catch the individual exceptions (e.g., *Fits.FitsError*).\n\n## Contribute\n\nIf you use SLiPy or have your own code related to spectroscopy or computing\nfor astronomy and think it would be a useful addition (or you find a\nbug/mistake) I'm more than open to suggested contributions/additions.\n\n## Author(s)\n\n[Geoffrey Lentner](http://glentner.github.io), B.S.  \nGraduate Research Assistant  \nDepartment of Physics \u0026 Astronomy  \nUniversity of Louisville\n\nSignificant intellectual contributions have been made by my thesis advisor,\nspecifically in terms of the science behind much of this package.\n\n[James Lauroesch](http://www.physics.louisville.edu/jtl/), Ph.D.  \nAssociate Professor  \nDepartment of Physics \u0026 Astronomy  \nUniversity of Louisville\n\n\n## Acknowledge SLiPy\n\nIf you have made use of SLiPy in your project/research, you can acknowledge\nyour use in the following ways:\n\n**Publications**  \nThis research has made use of SLiPy, an open source spectroscopy and\nastrophysics library for Python 3 (G. Lentner, 2015).\n\n**Projects**  \nIf your code either makes use of or borrows from SLiPy, a good way to reference\nthis is with a [shield](http://shields.io) in your README file.\n\n[![SLiPy](http://img.shields.io/badge/running-SLiPy-green.svg?style=flat)](http://glentner.github.io/SLiPy)\n\nThe above badge is generated using the following snippet\n```\n[![SLiPy](http://img.shields.io/badge/running-SLiPy-green.svg?style=flat)](http://glentner.github.io/SLiPy)\n```\n\n# Documentation\n\n\u003cbr\u003e\n\u003ca name=SpectrumLoc\u003e\u003c/a\u003e\n\n[Spectrum](SLiPy/Spectrum.py)\n-----------------------------\n\nObjects for representing astronomical data. Currently, this includes the\n*Spectrum* class and it's helper function *WaveVector*.\n\n\u003ca name=WaveVectorLoc\u003e\u003c/a\u003e\n- **WaveVector** ( *rpix*, *rval*, *delt*, *npix* ):\n\n    Construct numpy array of wavelength values where *rpix* is the reference\n    pixel index, *rval* is the wavelength at reference pixel, *delt* is the\n    resolutions (delta lambda), and *npix* is the length of desired array.\n\n\u003ca name=SpectrumLoc\u003e\u003c/a\u003e\n- class **Spectrum** ( \\**args*, \\*\\**kwargs* ):\n\n\tThe Spectrum object is a container class for a data array and its\n\tcorresponding wavelength array.\n\n\tThere are a few ways to create a Spectrum. If a single string\n\targument is given, it is taken as a file name and used to read in\n\tdata from a FITS file. With the keyword argument *wavecal* set as\n\tTrue (the default case), elements are read from the header to create\n\ta corresponding wavelength array to go with the data.\n\n    | Options   | Defaults       | Descriptions                   |\n    |-----------|----------------|--------------------------------|\n    | *wavecal* | True           | fit wavelength vector to data  |\n    | *crpix1*  | 'crpix1'       | reference pixel header keyword |\n    | *crval1*  | 'crval1'       | value at reference pixel       |\n    | *cdelt1*  | 'cdelt1'       | resolution (delta lambda)      |\n    | *xunits*  | 'Angstrom'     | units for wavelength array     |\n    | *yunits*  | ''             | units for data array           |\n\n\t\u003cbr\u003e\n\tIf an array-like object is given, it is converted to a numpy array and\n\ttaken as the spectrum data. A wavelength array will be generated that\n\tis simply an index (pixel) count. But if a second argument is provided,\n\tit will serve as the wavelength array. These must be equal in length\n\thowever.\n\n\tUnits will be imposed for these arrays. When initialized from a file,\n\tthe default units are *Angstrom* and *dimensionless_unscaled* for the\n\twavelength and data arrays respectively. Alternatives can be applied\n\tby providing the keyword arguments *xunits* and *yunits*. If\n\tinitialized via an array-like object, *dimensionless_unscaled* will\n\tonly be applied if no units are detected. If no wavelength array is\n\tprovided, the generated wavelength array will have *pixel* units.\n\tUnits are again only applied if none are detected for the given array.\n\n\tAddition, subtraction, multiplication, and division (including in-place\n\toperations, e.g., '+=') are defined for both spectrum on spectrum\n\toperations as well as scalar operations. When two spectra are operated on,\n\tthe LHS spectrum takes precedent. One of the spectra must be contained\n\twithin the other (i.e., their wavelength domain is either equal to or\n\tentirely interior to the other). The outer spectrum is resampled onto the\n\tinner spectrum's pixel space and the operation is applied element-wise.\n\tTo state it briefly, only the affected region of the LHS spectrum is\n\toperated on. This makes units dangerous for multiplication and division.\n\tOnly in the case of multiplying/dividing spectra of equivilent wavelength\n\tarrays will the units be properly applied. Otherwise, the RHS units will\n\tbe ignored. Considering the physical context within which it makes sense\n\tto apply these operations to spectra this is justified; the data will have\n\t`dimensionless` units in all likelihood. For scalar addition and\n\tsubtraction, if no units are given the units are implied to be the same as\n\tthat of the data.\n\n\tThe comparison operations ( \u003e, \u003c, \u003e=, \u003c=, ==, !=, \u0026, ^, | ) are defined\n\tto return a binary Spectrum of dimensionless 1's and 0's. The same\n\tconvention applies as above. Either the LHS or RHS must be contained within\n\tthe other, and the LHS is compared on the overlapping regions. Data outside\n\tthis overlapping region is returned as False.\n\n\tThe shift operations ('\u003e\u003e' and '\u003c\u003c') are defined to mean a shift in the\n\tspectrum. The addition and subtraction operate on the *data*. These\n\toperations apply to the *wave* array. `Spectrum \u003c\u003c 2 * u.Angstrom` says\n\tto blue shift the spectrum by 2 Angstroms. If the RHS is a dimensionless\n\tnumber, the wavelength units are implied. Also, one can shift a spectrum\n\tby another spectrum (e.g., `spectrumA \u003e\u003e spectrumB`), where the *wave*\n\tarrays would be operated on only. In these cases, they should\n\thave the same number of pixels! Finally, to get a variable shift across\n\tthe spectrum without creating a whole spectrum with junk data, you can\n\tshift using a numpy array (also of equal length). If no units are detected,\n\tthe wavelength units will be implied.\n\n\tOther operations:\n\t```python\n\t# The wavelength domain of A is either equal to or contained by B.\n\t# Returns True or False\n\tSpectrumA in SpectrumB\n\t```\n\t```python\n\t# Returns number of pixels\n\tlen(Spectrum)\n\t```\n\t```python\n\t# Calls str() on member arrays, (e.g., print(Spectrum))\n\tstr(Spectrum)\n\t```\n\n\tAlso, you can access the spectrum data via \"index\" notation. The behavior\n\tis not the same though. See the below interactive demonstration.\n\n\t```python\n\tIn [1]: from slipy import Spectrum \\\n\t   ...: from astropy import units as u \\\n\t   ...: import numpy as np\n\n\tIn [2]: x = np.linspace(-2*np.pi, 2*np.pi, 25) # -2pi \u003c x \u003c 2pi\n\n\tIn [3]: y = np.sin( np.pi * x ) / (np.pi * x)   # sinc(pi x)\n\n\tIn [4]: s = Spectrum(y)\n\n\tIn [5]: # display spectrum \\\n\t   ...: s\n\tOut[5]:\n\t[ 0.03935584 -0.05252603  0.00796074  0.0597675  -0.07945138  0.0079739\n\t  0.11489588 -0.17056501  0.00798048  0.82957457  0.82957457  0.00798048\n\t -0.17056501  0.11489588  0.0079739  -0.07945138  0.0597675   0.00796074\n\t -0.05252603  0.03935584]\n\t[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.  15.\n\t  16.  17.  18.  19.  20.] pix\n\n\tIn [9]: # where no units are given, they are implied. \\\n\t   ...: s[2]\n\tOut[9]: \u003cQuantity -0.05252602557386098\u003e\n\n\tIn [10]: # that was not the second element of the spectrum, but the signal \\\n\t   ....: # at the location `2 pix`. Accessing the spectrum where it is not \\\n\t   ....: # defined returns a linear approximation to it between the two \\\n\t   ....: # pixels that surround it. \\\n\t   ....: s[2.5]\n\tOut[10]: \u003cQuantity -0.02228264076183217\u003e\n\n\tIn [11]: # units are an acceptable access method, so long as they can be \\\n\t   ....: # converted (e.g., u.nm -\u003e u.Angstrom) \\\n\t   ....: s[2.5 * u.pixel]\n\tOut[11]: \u003cQuantity -0.02228264076183217\u003e\n\n\tIn [12]: # Slicing the spectrum works in two ways. If no `step` is given \\\n\t   ....: # than the `start` and `stop` act as a domain for which we \\\n\t   ....: # want to truncate the spectrum outside of. \\\n\t   ....: s[2:4]\n\tOut[12]:\n\t[-0.05252603  0.00796074  0.0597675 ]\n\t[ 2.  3.  4.] pix\n\n\tIn [13]: s[2.5:4.5]\n\tOut[13]:\n\t[ 0.00796074  0.0597675 ]\n\t[ 3.  4.] pix\n\n\tIn [14]: s[:4]\n\tOut[14]:\n\t[ 0.03935584 -0.05252603  0.00796074  0.0597675 ]\n\t[ 1.  2.  3.  4.] pix\n\n\tIn [15]: s[15:]\n\tOut[15]:\n\t[ 0.0079739  -0.07945138  0.0597675   0.00796074 -0.05252603  0.03935584]\n\t[ 15.  16.  17.  18.  19.  20.] pix\n\n\tIn [16]: # With a `step` size the behavior is entirely different. \\\n\t   ....: # We are asking instead to `resample` the spectrum. The  \\\n\t   ....: # `step` value acts as a desired resolution. As with the \\\n\t   ....: # accessor methods, the gaps are filled with linear      \\\n\t   ....: # approximations \\\n\t   ....: s[1:3:0.5]\n\tOut[16]:\n\t[ 0.03935584 -0.00658509 -0.05252603 -0.02228264  0.00796074]\n\t[ 1.   1.5  2.   2.5  3. ] pix\n\n\tIn [17]: s = s[:4] \\\n\t   ....: s\n\tOut[17]:\n\t[ 0.03935584 -0.05252603  0.00796074  0.0597675 ]\n\t[ 1.  2.  3.  4.] pix\n\n\tIn [18]: # Without a `start` and a `stop` we just resample. \\\n\t   ....: s[::0.5]\n\tOut[18]:\n\t[ 0.03935584 -0.00658509 -0.05252603 -0.02228264  0.00796074  0.03386412\n\t  0.0597675 ]\n\t[ 1.   1.5  2.   2.5  3.   3.5  4. ] pix\n\n\tIn [19]: s = Spectrum(y) \\\n\t   ....: s\n\tOut[19]:\n\t[ 0.03935584 -0.05252603  0.00796074  0.0597675  -0.07945138  0.0079739\n\t  0.11489588 -0.17056501  0.00798048  0.82957457  0.82957457  0.00798048\n\t -0.17056501  0.11489588  0.0079739  -0.07945138  0.0597675   0.00796074\n\t -0.05252603  0.03935584]\n\t[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.  15.\n\t  16.  17.  18.  19.  20.] pix\n\n\tIn [20]: # The boundaries take precident however, and not every resolution \\\n\t   ....: # makes physical sense with the requested boundaries. When no     \\\n\t   ....: # edges are specified, they default to the current boundaries.    \\\n\t   ....: # There are only 19 pixels, so we won't get what you might think  \\\n\t   ....: # the expected behavior is. Here, 5 doesn't go evenly into the    \\\n\t   ....: # existing domain, so we simply choose the closest thing.\n\t   ....: s[::5]\n\tOut[20]:\n\t[ 0.03935584  0.01974225  0.01974225  0.03935584]\n\t[  1.           7.33333333  13.66666667  20.        ] pix\n\n\t```\n\n    \u003cbr\u003e\n    Member functions:\n\n    - *resample* ( \\**args*, *kind* = 'linear' ):\n\n        If given a single argument, it is taken to be a *Spectrum* object,\n        and *self* is resampled onto the pixel space of the other spectrum.\n        Otherwise, three arguments are expected. The first and second argument\n        should define the lower and upper wavelength value of a domain,\n        respectively. The third argument should be the number of elements\n        (pixels) for the new domain. Think numpy.linspace(). *kind* is passed\n\t\tto scipy...interp1d.\n\n\t\t```python\n\t\tspectrumA.resample(spectrumB, kind = 'cubic')\n\n\t\tspectrumA.resample( 585 * u.nm, 5950 * u.Angstrom, 1e4 + 1 )\n\t\t```\n\n\t- *insert* ( *other*, *kind* = 'linear'):\n\n\t\tGiven a Spectrum, *other*, contained within the wavelength domain\n\t\tof *self*, replace all pixels in the overlapping region with that\n\t\tof an interpolation built on *other*. *kind* is passed to interp1d.\n\n\t\t```python\n\t\tspectrumA.insert(spectrumB, kind = 'quadratic')\n\t\t```\n\n    - *copy* ():\n\n        Essentially a wrapper to *deepcopy()*. To say SpectrumA = SpectrumB\n        implies that SpectrumA *is* SpectrumB. If you want to create a new\n        spectrum *equal* to another, say SpectrumA = SpectrumB.copy()\n\n\n\u003cbr\u003e\n\u003ca name=FitsLoc\u003e\u003c/a\u003e\n\n[Fits](SLiPy/Fits.py)\n---------------------\n\nManipulate FITS files. Import data into *Spectrum* objects. Filter results\nby right ascension and declination. Grab header elements. Search for attributes\nof the data such as distance, spectral type, etc.\n\n\u003ca name=FindLoc\u003e\u003c/a\u003e\n- **Find** (*toplevel* = './', *pattern* = '\\*.fits'):\n\n    Search for file paths below *toplevel* fitting *pattern*. Returns a list\n    of string values.\n\n\u003ca name=RFindLoc\u003e\u003c/a\u003e\n- **RFind** (*toplevel* = './', *pattern* = '\\*.fits'):\n\n    Recursively search for file paths below *toplevel* fitting *pattern*.\n    Returns a list of string values.\n\n\u003ca name=GetDataLoc\u003e\u003c/a\u003e\n- **GetData** ( \\**files*, \\*\\**kwargs*):\n\n\tImport data from FITS *files*. Returns a list of *Spectrum* objects.\n\n    |Options     | Defaults        | Descriptions\n    |------------|-----------------|------------------------------------------|\n    |*verbose*   | True            | display messages, progress               |\n    |*toplevel*  | ''              | request import from directory *toplevel* |  \n    |*pattern*   | '\\*.fits'       | pattern matching with *toplevel*         |\n    |*recursive* | False           | search recursively below *toplevel*      |\n    |*wavecal*   | True            | fit wavelength vector to data            |\n    |*crpix1*    | 'crpix1'        | reference pixel header keyword           |\n    |*crval1*    | 'crval1'        | value at reference pixel                 |\n    |*cdelt1*    | 'cdelt1'        | resolution (delta lambda)                |\n    |*xunits*    | 'Angstrom'      | wavelength units (astropy.units)         |\n    |*yunits*    | 'ergs cm-2 s-1' | units of the data                        |\n\n\u003ca name=HeaderLoc\u003e\u003c/a\u003e\n- **Header** ( *filename*, *keyword* = None, \\*\\**kwargs*):\n\n    Retrieve *keyword* from FITS header in file *filename*.\n    Return type depends on what is returned. If no keyword is\n\tgiven, the entire header object is returned.\n\n\u003ca name=SearchLoc\u003e\u003c/a\u003e\n- **Search** ( \\**files*, \\*\\**kwargs*):\n\n    Extract object names from Fits *files* and use Simbad module\n    to resolve the *attribute* (a required keyword argument)\n    from the SIMBAD astronomical database. Currently available attributes\n    are 'Position', 'Distance', 'Sptype', and 'IDList'. Returns a list of\n    results (type depends on the values).\n\n    | Options     | Defaults  | Descriptions                         |\n    |-------------|-----------|--------------------------------------|\n    | *verbose*   | True      | display messages, progress           |\n    | *toplevel*  | None      | search under *toplevel* directory    |\n    | *pattern*   | '\\*.fits' | for files under *toplevel*           |\n    | *recursive* | False     | search recusively under *toplevel*   |\n    | *attribute* | None      | attribute to search for (no default) |\n\n\u003ca name=PositionSortLoc\u003e\u003c/a\u003e\n- **PositionSort** ( *center*, *radius*, \\**files*, \\*\\**kwargs* ):\n\n    Return a list of files from *files* that lie in a *radius* (in\n    decimal degrees) from *center*, based on the *ra* (right ascension) and\n    *dec* (declination).\n\n    | Options   | Defaults | Descriptions                             |\n    |-----------|----------|------------------------------------------|\n    *ra*        | 'pos1'   | header element for right ascension       |\n    *dec*       | 'pos2'   | header element for declination           |\n    *obj*       | 'object' | header element for object id             |\n    *raconvert* | True     | convert decimal hours to decimal degrees |\n    *verbose*   | True     | display messages, progress               |\n    *toplevel*  | None     | *toplevel* directory to look for files   |\n    *recursive* | False    | search below *toplevel* recursively      |\n    *pattern*   |'\\*.fits' | glob *pattern* for file search           |\n    *useSimbad* | False    | use *Simbad* instead of header elements  |\n\n\n\u003cbr\u003e\n\u003ca name=SimbadLoc\u003e\u003c/a\u003e\n\n[Simbad](SLiPy/Simbad.py)\n-------------------------\n\nThis module allows the user to query the SIMBAD astronomical database from\ninside Python or shell commands/scripts. It's four current major functions\n*Position*, *Distance*, *Sptype*, and *IDList* return real variables with\nappropriate types ready for use.\n\nAs a shell script:\n\n```\n$ Simbad.py\n\n usage: Simbad.py @Attribute \u003cidentifier\u003e [**kwargs]\n\n The 'Attribute' points to a function within this module and indicates\n what is to be run. Execute 'Simbad.py @Attribute help' for usage details of\n a specific function. Currently available attributes are: `Position`,\n `Distance`, `Sptype` and `IDList`.\n\n The identifier names can be anything recognized by SIMBAD (e.g., Regulus,\n \"alpha leo\", \"HD 121475\", \"del cyg\", etc ...) if the name is two parts make\n sure to use quotation to enclose it.\n\n The **kwargs is the conventional reference to Python keyword arguments.\n These should be specific to the 'Attribute' being pointed to.\n```\n\n\u003ca name=PositionLoc\u003e\u003c/a\u003e\n- **Position** ( *identifier*, \\*\\**kwargs* ):\n\n    Return the right ascension and declination in decimal degrees of\n    *identifier* as a pair.\n\n    | Options   | Defaults    | Descriptions                     |\n    |-----------|-------------|----------------------------------|\n    | *parse*   | True        | parse return file from SIMBAD    |\n    | *full*    | False       | return more detailed information |\n\n    \u003cbr\u003e\n    Example:\n    ```python\n    ra, dec = Simbad.Position('Sirius')\n    ```\n\n\u003ca name=DistanceLoc\u003e\u003c/a\u003e\n- **Distance** ( *identifier*, \\*\\**kwargs* ):\n\n    Return the distance in parsecs to *identifier*.\n\n    | Options   | Defaults    | Descriptions                     |\n    |-----------|-------------|----------------------------------|\n    | *parse*   | True        | parse return file from SIMBAD    |\n    | *full*    | False       | return more detailed information |\n\n    \u003cbr\u003e\n    Example:\n    ```python\n    distance = Simbad.Distance('rigel kent')\n    ```\n\n\u003ca name=SptypeLoc\u003e\u003c/a\u003e\n- **Sptype** ( *identifier*, \\*\\**kwargs* ):\n\n    Return the spectral type of *identifier* as resolved by SIMBAD.\n\n    | Options   | Defaults    | Descriptions                     |\n    |-----------|-------------|----------------------------------|\n    | *parse*   | True        | parse return file from SIMBAD    |\n    | *full*    | False       | return more detailed information |\n\n    \u003cbr\u003e\n    Example:\n    ```python\n    # returns 'B8IVn' (HD 87901 is Regulus)\n    sptype = Simbad.Sptype('HD 87901')\n    ```\n\n\u003ca name=IDListLoc\u003e\u003c/a\u003e\n- **IDList** ( *identifier*, \\*\\**kwargs* ):\n\n    Return a list of alternate IDs for *identifier*.\n\n    | Options   | Defaults    | Descriptions                     |\n    |-----------|-------------|----------------------------------|\n    | *parse*   | True        | parse return file from SIMBAD    |\n    | *full*    | False       | return more detailed information |\n\n    \u003cbr\u003e\n    Example:\n    ```python\n    other_names = Simbad.IDList('proxima centauri')\n    ```\n\n\n\u003cbr\u003e\n\u003ca name=CorrelateLoc\u003e\u003c/a\u003e\n\n[Correlate](SLiPy/Correlate.py)\n-------------------------------\n\nCorrelation functions for astronomical data.\n\n\u003ca name=XCorrLoc\u003e\u003c/a\u003e\n- **XCorr** ( *spectrumA*, *spectrumB*, \\*\\**kwargs* ):\n\n    The function returns an integer value representing the best shift within\n    a *lag* based on the computed RMS of each configuration.\n\n    | Options   | Defaults    | Descriptions                     |\n    |-----------|-------------|----------------------------------|\n    | *lag*     | 25          | pixel range to shift over        |\n\n\n\u003cbr\u003e\n\u003ca name=TelluricLoc\u003e\u003c/a\u003e\n\n[Telluric](SLiPy/Telluric.py)\n-----------------------------\n\nRemoval of atmospheric absorption lines in spectra.\n\n\u003ca name=CorrectLoc\u003e\u003c/a\u003e\n- **Correct** ( *spectrum*, \\**calibration*, \\*\\**kwargs* ):\n\n\tPerform a telluric correction on *spectrum* with one or more\n\t*calibration* spectra. If more than one calibration spectrum is\n\tprovided, the one with the best fit after performing both a\n\thorizontal cross correlation and a vertical amplitude fit is used.\n\tThe spectrum and all the calibration spectra must have the same\n\tnumber of pixels (elements). If a horizontal shift in the calibration\n\tspectra is appropriate, only the corresponding range of the spectrum\n\tis divided out!\n\n    **Notice** Your spectra must be continuum normalized for this to work!\n\n    | Options   | Defaults        | Descriptions                         |\n    |-----------|-----------------|--------------------------------------|\n    | *lag*     | 25              | pixel range to shift over            |\n    | *range*   | (0.5, 2.0, 151) | numpy.linspace for amplitude fitting |\n\n    ![example](Figures/HD192640.png)\n\n    **Figure 1:** The above figure is an example of applying the\n    **Telluric.Correct()** algorithm to a spectrum. In this case, six spectra of\n    *Regulus* from the Elodie archive were used as calibration spectra.\n\n\n\u003cbr\u003e\n\u003ca name=VelocityLoc\u003e\u003c/a\u003e\n\n[Velocity](SLiPy/Velocity.py)\n-----------------------------\n\nRadial velocity corrections for 1D spectra.\n\n\u003ca name=HelioCorrectLoc\u003e\u003c/a\u003e\n- **HelioCorrect** ( *observatory*, \\**spectra*, \\*\\**kwargs* ):\n\n    Perform heliocentric velocity corrects on *spectra* based on\n    *observatory* parameters (*longitude*, *latitude*, *altitude*) and the\n    member attributes, *ra* (right ascension), *dec* (declination), and *jd*\n    (julian date) from the *spectra*. These should all have units.\n\n    | Options    | Defaults        | Descriptions               |\n    |------------|-----------------|----------------------------|\n    | *verbose*  | False           | display messages, progress |\n\n\u003ca name=BaryCorrectLoc\u003e\u003c/a\u003e\n- **BaryCorrect** ( *observatory*, \\**spectra*, \\*\\**kwargs* ):\n\n    Perform barycentric velocity corrects on *spectra* based on\n    *observatory* parameters (*longitude*, *latitude*, *altitude*) and the\n    member attributes, *ra* (right ascension), *dec* (declination), and *jd*\n    (julian date) from the *spectra*. These should all have units.\n\n    | Options    | Defaults        | Descriptions               |\n    |------------|-----------------|----------------------------|\n    | *verbose*  | False           | display messages, progress |\n\n\u003ca name=IrafInputLoc\u003e\u003c/a\u003e\n- **IrafInput** ( \\**files*, \\*\\**kwargs* ):\n\n\tBuild an input file for IRAF's rvcorrect task.\n\n\t*files* should be a list of FITS file names to build the output table for.\n\tThe user can optionally specify a *toplevel* directory to search for files\n    under. If *outfile* is given, write results to the file.\n\n    | Options     | Defaults  | Descriptions                          |\n    |-------------|-----------|---------------------------------------|\n    | *toplevel*  | None      | search *toplevel* directory for files |\n    | *pattern*   | '\\*.fits' | pattern matching under *toplevel*     |\n    | *recursive* | False     | search recusively under *toplevel*    |\n    | *outfile*   | None      | write lines to file named *outfile*   |\n\n\n\u003cbr\u003e\n\u003ca name=ObservatoryLoc\u003e\u003c/a\u003e\n\n[Observatory](SLiPy/Observatory.py)\n-----------------------------------\n\nDefine observatory parameter similar to the IRAF task. All observatories\nshould follow the following pattern. The user can add as many as they like\nto this module. I welcome suggestions.\n\n\u003ca name=OHPLoc\u003e\u003c/a\u003e\n```Python\nclass OHP(Observatory):\n    \"\"\"\n    The Observatoire de Haute-Provence, France.\n    \"\"\"\n    def __init__(self):\n        self.name       = 'Observatoire de Haute-Provence'\n        self.longitude  = 356.28667  * u.degree # West\n        self.latitude   = 43.9308334 * u.degree # North\n        self.altitude   = 650        * u.meter\n        self.timezone   = 1          * u.hourangle\n        self.resolution = 42000\n```\n\nThere are currently 69 defined observatories:\n\n| Class ID       | Observatory Name                                         |\n|----------------|----------------------------------------------------------|\n|            OHP |              The Observatoire de Haute-Provence, France. |\n|           KPNO |                           Kitt Peak National Observatory |\n|           WIYN |                                         WIYN Observatory |\n|           CTIO |                   Cerro Tololo Interamerican Observatory |\n|        LASILLA |                 European Southern Observatory: La Silla. |\n|        PARANAL |                   European Southern Observatory: Paranal |\n|           LICK |                                         Lick Observatory |\n|           MMTO |                                          MMT Observatory |\n|           CFHT |                           Canada-France-Hawaii Telescope |\n|        LAPALMA |                        Roque de los Muchachos, La Palma. |\n|            MSO |                                  Mt. Stromlo Observatory |\n|            SSO |                                Siding Spring Observatory |\n|            AAO |                             Anglo-Australian Observatory |\n|       MCDONALD |                                     McDonald Observatory |\n|            LCO |                                 Las Campanas Observatory |\n|      MTBIGELOW |                  Catalina Observatory: 61 inch telescope |\n|            DAO |                       Dominion Astrophysical Observatory |\n|            SPM |     Observatorio Astronomico Nacional, San Pedro Martir. |\n|           TONA |         Observatorio Astronomico Nacional, Tonantzintla. |\n|        PALOMAR |                                       The Hale Telescope |\n|            MDM |                       Michigan-Dartmouth-MIT Observatory |\n|            NOV |                        National Observatory of Venezuela |\n|            BMO |                              Black Moshannon Observatory |\n|            BAO |                             Beijing XingLong Observatory |\n|           KECK |                                   W. M. Keck Observatory |\n|           EKAR |                               Mt. Ekar 182 cm. Telescope |\n|            APO |                                 Apache Point Observatory |\n|         LOWELL |                                       Lowell Observatory |\n|            VBO |                                  Vainu Bappu Observatory |\n|            IAO |                   Indian Astronomical Observatory, Hanle |\n|           FLWO |                                      Whipple Observatory |\n|          FLWO1 |                                      Whipple Observatory |\n|            ORO |                                    Oak Ridge Observatory |\n|            LNA |             Laboratorio Nacional de Astrofisica - Brazil |\n|           SAAO |                   South African Astronomical Observatory |\n|         CASLEO |              Complejo Astronomico El Leoncito, San Juan. |\n|         BOSQUE |             Estacion Astrofisica Bosque Alegre, Cordoba. |\n|         ROZHEN |     National Astronomical Observatory Rozhen - Bulgaria. |\n|           IRTF |                         NASA Infrared Telescope Facility |\n|          BGSUO |                    Bowling Green State Univ Observatory. |\n|           DSAZ |     Deutsch-Spanisches Observatorium Calar Alto - Spain. |\n|             CA |                                   Calar Alto Observatory |\n|           HOLI |  Observatorium Hoher List (Universitaet Bonn) - Germany. |\n|            LMO |                            Leander McCormick Observatory |\n|            FMO |                                 Fan Mountain Observatory |\n|         WHITIN |                     Whitin Observatory,Wellesley College |\n|            OSN |                            Observatorio de Sierra Nevada |\n|   GEMINI NORTH |                                 Gemini North Observatory |\n|   GEMINI SOUTH |                                 Gemini South Observatory |\n|        LASILLA |                 European Southern Observatory: La Silla. |\n|        PARANAL |                  European Southern Observatory: Paranal. |\n|         ESONTT |            European Southern Observatory, NTT, La Silla. |\n|         ESO36M | European Southern Observatory, 3.6m Telescope, La Silla. |\n|         ESOVLT |             European Southern Observatory, VLT, Paranal. |\n|            SLN |                 SLN - Catania Astrophysical Observatory. |\n|            EUO |                               Ege University Observatory |\n|            TNO |                             Turkiye National Observatory |\n|            TUG |                    TUBITAK National Observatory, Turkey. |\n|            MGO |                                 Mount Graham Observatory |\n|          ARIES | Aryabhatta Research Institute of Observational Sciences. |\n|           OALP |                     Observatorio Astronomico de La Plata |\n|           OLIN |                   Connecticut College - Olin Observatory |\n|         BOYDEN |                                       Boyden Observatory |\n|          LULIN |                                        Lulin Observatory |\n|           SOAR |               Southern Astrophysical Research Telescope. |\n|          BAKER |                                        Baker Observatory |\n|            HET |           McDonald Observatory - Hobby-Eberly Telescope. |\n|           JCDO |        Jack C. Davis Observatory, Western Nevada College |\n|            LNO |                            Langkawi National Observatory |\n\n\n\u003cbr\u003e\n\u003ca name=PlotLoc\u003e\u003c/a\u003e\n\n[Plot](SLiPy/Plot.py)\n---------------------\n\nConvenient wrapper to matplotlib for plotting spectra. A *SPlot* is simply a manager\nof figure attributes, to quickly go from looking\nat one spectra to another. One can also *overlay* spectra.\n\n\u003ca name=SPlotLoc\u003e\u003c/a\u003e\n- class **SPlot** ( *spectrum*, \\*\\**kwargs* ):\n\n    Spectrum Plot - Create figure of *spectrum*.\n\n    | Options  | Defaults   | Descriptions         |\n    |----------|------------|----------------------|\n    | *marker* | 'b-'       | marker for data      |\n    | *label*  | 'spectrum' | name of object       |\n    | *usetex* | False      | render with pdflatex |\n\n    \u003cbr\u003e\n    The following member functions call matplotlib.pyplot equivalent:  \n    **xlim**, **ylim**, **xlabel**, **ylabel**, **title**, **legend**,\n    **text**, **grid**, **close**, **tight_layout**.\n\n    Here, when these function are called, the arguments are passed to\n    matplotlib; however, these calls are remembered. So when you go to *draw*\n    the figure again, you are back where you left off.\n\n    - *draw*( ):\n\n        Rebuild and render the figure.\n\n    - *refresh*( ):\n\n        Re-render (refresh) the figure, without clearing the axis.\n\n    - *txtclear*( ):\n\n        Clear all the calls to *text*( ) from the figure.\n\n    - *xoffset*( *value* ):\n\n        Switch either on or off (*value* = True | False) the horizontal offset.\n\n    - *yoffset*( *value* ):\n\n        Switch either on or off (*value* = True | False) the vertical offset.\n\n    - *overlay*( \\**splots* ):\n\n        Given one or more *splots*, *overlay* the figures.\n\n    - *markers*( \\**args* ):\n\n        Reassign the values for the `marker`s in the figure. The number\n        of arguments must equal the number of spectra in the figure.\n\n    - *restore*( ):\n\n        Restore the figure to only the original spectrum.\n\n    - *save*( *filename* ):\n\n        Save the figure to a file called *filename*. The file format is derived\n        from the extension of *filename*.\n\n\u003ca name=IterateLoc\u003e\u003c/a\u003e\n- **Iterate**( \\**splots*, \\*\\**kwargs* ):\n\n    Iterate thru *splots* to inspect data, the user marks spectra of\n    interest. The function returns a list of *keepers*.\n\n    | Options | Defaults  | Descriptions          |\n    |---------|-----------|-----------------------|\n    | *keep*  | 'name'    | alternative is 'plot' |\n\n    \n    **Example:**\n    ```python\n    from slipy import Fits, Plot\n\n    fpath = '?' # toplevel directory name where your FITS files are\n    files = Fits.Find(fpath)\n\n    spectra = Fits.GetData( *files )\n\n    figure = [\n\n        Plot.SPlot( spectrum, label=Fits.Header(fname, 'object') )\n        for spectrum, fname in zip(spectra, files)\n    ]\n\n    keepers = Plot.Iterate( *figure )\n    # enter either 'y', 'n', or 'x' as prompted by the terminal\n    ```\n\n\n\u003cbr\u003e\n\u003ca name=ProfileLoc\u003e\u003c/a\u003e\n\n[Profile](SLiPy/Profile.py)\n---------------------------\n\nProfile fitting tasks for spectra.\n\n\u003ca name=SelectLoc\u003e\u003c/a\u003e\n- **Select** ( *splot* ):\n\n    Select points from the *splot*. This should be of type SPlot\n    (or it can optionally be a Spectrum type, for which a SPlot will be\n    created). The splot will be rendered and the user clicks on the\n    figure. When finished, return to the terminal prompt. A dictionary is\n    returned with two entries, *wave* and *data*, representing the x-y\n    locations selected by the user. This can always be retrieved later by\n    accessing the module member *Profile.selected*.\n\n    While the user makes selections, temporary markers appear on the figure\n    indicating the data point that was just selected. If a mark does not\n    appear, try moving the curser slightly and trying again. Even if the line\n    goes through that point, there might not actually be data there.\n\n\u003ca name=FitLoc\u003e\u003c/a\u003e\n- **AutoFit** ( *splot*, *function* = InvertedLorentzian, *params* = None)\n\n    Given a *splot* of type Plot.SPlot, the user selects four points on the\n    spectrum and a parameterized function is fit (an inverted Lorentzian by\n    default). Optionally, *splot* can be of type spectrum and a basic SPlot\n    will be created for you. If the user gives an alternative *function*,\n    *params* (parameters) must be provided. *params* is to be the first guess,\n    *p0* given to scipy...curve_fit; the user can provide them expicitely,\n    or in the form of functions with the templates `f(x, y)`\n    where *x* and *y* are the *wave* and *data* arrays (respectively) extracted\n    between the two inner points selected by the user.\n\n\t*InvertedLorentian* is defined in SLiPy.Algorithms.Functions. The user does\n\tnot need to provide *params* for the default behavior.\n\n\t**Example:**\n\t```python\n\t# In this example I use an alternative function simply as an illustration.\n\t# Here `spectrum` is a Spectrum object that has been imported and calibrated ...\n\n\tfrom slipy import Spectrum, Plot, Profile\n\tfrom astropy import units as u\n\n\n\t# create a SPlot figure\n\tfig = Plot.SPlot(spectrum, label='HD332329', marker='k-')\n\tfig.xlabel('Wavelength (Angstrom)', labelpad=20)\n\tfig.ylabel('Normalized Flux', labelpad=20)\n\tfig.xlim(5885, 5905)\n\tfig.legend(frameon=False)\n\n\t# Now we need to define some parameter functions to pass to Profile.Fit()\n\t# with our user function\n\tfrom slipy.Algorithms.Functions import InvertedGaussian\n\n\t# best guess for amplitude of gaussian\n\tdef A(x, y):\n\t\treturn 1 - y.min().value\n\n\t# best guess for mean of gaussian\n\tdef mu(x, y):\n\t\treturn x[ y.argmin() ].value\n\n\t# best guess for standard deviation of gaussian\n\tdef sigma(x, y):\n\t\treturn y.std().value\n\n\t# call the Profile.Fit() function with our user defined parameterization\n\tline = Profile.AutoFit(fig, function=InvertedGaussian, params=[A, mu, sigma])\n\n\t# Please select four points identifying the spectral line.\n\t# Outer points mark the domain of the line.\n\t# Inner points mark the sample of the line to fit.\n\t# Press \u003cReturn\u003e after making your selections ...\n\n\t# now `line` is a Spectrum object generated by evaluating the\n\t# `InvertedGaussian` function on the larger domain selected by the\n\t# user with coefficients optimized using Profile.AutoFit().\n\n\t# save the figure ...\n\tfig.tight_layout()\n\tfig.xoffset(False)\n\tfig.refresh()\n\tfig.save('HD332329.png')\n\t```\n\n    ![example](Figures/Profile-Fit.png)\n\n    **Figure 2:** The above figure was generated by running the above code\n\tsnippet.\n\n\u003ca name=ExtractLoc\u003e\u003c/a\u003e\n- **Extract** ( *splot*, *kernel* = Gaussian, \\*\\**kwargs*):\n\n    Select locations in the *splot* figure, expected to be of type SPlot.\n    Exactly four points should be selected. These are used to extract a\n    line profile from the spectrum plotted in the splot figure. The inner\n    section is used for the line, and the outer intervals are used to model\n    the continuum; these, respectively, are both returned as Spectrum objects.\n    The gap is jumped using 1D interpolation (scipy...interp1d). In order\n\tto get a smooth continuum and error estimates, this function uses\n\tnon-parametric kernel regression (a.k.a. kernel smoothing) to fit a\n\tcurve through the data marked as continuum. Be default, the kernel\n\tfunction is the Gaussian. The user can actually use a different, user\n\tdefined kernel function, but it's template must match that of\n\tSLiPy.Algorithms.Functions.Gaussian. See the SLiPy.Algorithms.KernelFit\n\tmodule to better understand how this happens. The *bandwidth* is actually\n\tthe standard deviation in the Gaussian. It is a length scale that defines\n\thow influencial data is at a particular distance. The default bandwidth\n\twill almost definitely be too large (resulting in a largely flat result\n\tat the average of the data points). As the bandwidth decreases to smaller\n\tthan the resolution of the data, you will essentially being performing\n\tlinear interpolation (no smoothing). You want to choose a length that is\n\tlarger than the small scale variation in the noise, but smaller than the\n\tlarger scale variation in the overall continuum level.\n\n\tThe *rms* can optionally be computed between the continuum data and the\n\tcurve fit to it. This rms value is used to scale the error profile\n\tthat is returned for the line extracted. Explicitely, the error for a\n\tline extraction is `error_spectrum = continuum_rms * I_0 / I` where\n\t*I* is the line data and *I_0* is the interpolated continuum over the\n\tgap.\n\n\tFrom the documentation of scipy.interpolate...interp1d: *kind* specifies the\n\tkind of interpolation as a string ('linear', 'nearest', 'zero', 'slinear',\n\t'quadratic', 'cubic') where 'slinear', 'quadratic' and 'cubic' refer to a\n\tspline interpolation of first, second,  or third order respectively;  or as\n\tan integer specifying the order of the spline interpolator to use.\n\n    | Options      | Defaults   | Descriptions                            |\n    |--------------|------------|-----------------------------------------|\n    | *kind*       | 'cubic'    | given to scipy...interp1d for continuum |\n    | *bandwidth*  | 0.1 * u.nm | for kernel, user should provide this!   |\n    | *rms*        | False      | return an error estimate for the line   |\n\n    \u003cbr\u003e\n    **Example:**\n    ```python\n    # drawing from the previous example, but using HD200723 instead.\n\n    line, continuum, rms = Profile.Extract(fig, bandwidth=u.Angstrom/15, rms=True)\n\n    # Please select four points identifying the spectral line.\n    # Outer intervals sample the continuum.\n    # Center interval contains the line.\n    # Press \u003cReturn\u003e after making your selections ...\n    ```\n\n    ![example](Figures/Profile-Extract.png)\n\n    **Figure 3:** The above figure was generated by running the above code\n\tsnippet.\n\n\u003ca name=MultiFitLoc\u003e\u003c/a\u003e\n- **MultiFit** ( *splot*, *function* = 'Lorentzian', *observatory* = None,\n    *resolution* = None, \\*\\**kwargs*):\n\n    The MultiFit routine takes a *splot* figure (type SPlot) and allows the\n    user to interactively fit line profiles. *splot* may optionally be of type\n    Spectrum, in which case a SPlot figure will be created for you. This function\n    creates a *FittingGUI* object (not documented here) which uses the *Profile.Extract()*\n    routine first (*kwargs* as passed this function). As in the Extract routine, the user\n    will select four points that mark the boundaries of the line (blended or otherwise)\n    and some surrounding continuum to sample. The *KernelFit1D* routine is applied with the\n    user specified *bandwidth* to smooth the noise out of the continuum and interpolate, of\n    type *kind*, across the line. After this, the user is asked to further select points\n    marking the peaks of the line(s). The number of selection points indicates the number\n    of lines to be fit. If you wish to deblend two or more lines, select all suspected\n    locations. These are not only used to determine the number of lines to fit but to make\n    initial guesses at the parameters for each line.\n\n    After these selections, a slider for each parameter appears along with radio buttons for\n    each line. The user can interactively adjust the parameter(s) for a given line by\n    selecting it (the radio buttons) and dragging a slider. Each line is represented by a\n    black, dashed line in the plot. The currently selected line is bold. The super-position\n    (i.e., blended) lines are plotted with a solid green line.\n\n    Each slider is labeled on the left side with the name of the parameter it controls. At\n    the right of each slider is the current value of that parameter. The radio buttons are\n    labeled \"L1\", \"L2\", etc. for each line.\n\n    This routine returns a list of Spectrum objects. The length of the list is equal to the\n    number of lines that were fit. This routine functions as both a single line fitting tool\n    as well as a deblending tool.\n\n    **Example:**\n    ```python\n    # drawing from the above examples\n\n    L1, L2, L3, L4 = Profile.MultiFit(fig, function = 'Gaussian', bandwidth = u.Angstrom / 8)\n\n    #  We need to extract the lines from the continuum before we begin the fitting process.\n    # Please select four points identifying the spectral line.\n    # Outer intervals sample the continuum.\n    # Center interval contains the line.\n    # Press \u003cReturn\u003e after making your selections ...\n\n    # Now select the peaks of each line to be fit.\n    # Initial guesses will be made for each line markered.\n    # Press \u003cReturn\u003e after making your selections ...\n    ```\n\n    ![example](Figures/MultiFit.png)\n\n    **Figure 4:** Mid-session, annotated screen-shot of the above code-snippet/routine.\n\n\u003cbr\u003e\n\u003ca name=MontageLoc\u003e\u003c/a\u003e\n\n[Montage](SLiPy/Montage.py)\n---------------------------\n\n[Montage](http://montage.ipac.caltech.edu/) is a very powerful suite of C code\nfor creating image mosaics. This module is a wrapper to automate not only the\nprocess for small projects, but to segment large fields into a grid and\nmosaic each *site* before combining them into a *master* mosaic.\n\nAt the outset of the development of this module, the author was unaware of the\ncurrently available *montage_wrapper*. This module will no longer be developed.\nNevertheless, it remains a high level manager for creating mosaics.\n\nSee the example in Figure 5.\n\n\u003ca name=MSolveGridLoc\u003e\u003c/a\u003e\n- **SolveGrid** ( *sides*, *grid* ):\n\n\tHelper function for the Field and SubField classes. Both *sides* and *grid*\n\tneed to be array-like and of length two. *sides* is the side length of the\n\tfield in decimal degrees in right ascension and declination respectively.\n\t*grid* specifies the subdivision along these axis (e.g., (2,2) says 2x2).\n\n\tThe user should mindful of their choices. If the side lengths cannot be\n\tsubdivided into well-behaved (rational) segments, higher decimal places\n\twill be lost in the SubField.ArchiveList() task resulting in small\n\tgaps in the mosaic.\n\n\u003ca name=MMosaicLoc\u003e\u003c/a\u003e\n- **Mosaic** ( *resolution*, \\**folders*, \\*\\**kwargs* ):\n\n    Conduct standard build procedures for all *folders*, similar to the\n    [m101 example](http://montage.ipac.caltech.edu/docs/m101tutorial.html).\n    *resolution* is the number of pixels per degree for the output image.\n    Note: *folders* should be absolute paths. Further, below each of these\n    directories, there should already exist the standard folder structure\n    ```\n    folder/\n      |--images/\n      |    |-- \u003clocation of raw FITS images\u003e\n      |\n      |--projected/\n      |--differences/\n      |--corrected/\n      |--final/\n    ```\n\n    \u003cbr\u003e\n    The mosaic will be deposited at *final/mosaic.fits*.\n\n    | Options    | Defaults | Descriptions                             |\n    |------------|----------|------------------------------------------|\n    | *verbose*  | True     | display messages, progress               |\n    | *bkmodel*  | True     | model and correct for background effects |\n\n\n\u003ca name=MSubFieldLoc\u003e\u003c/a\u003e\n- class **SubField** ( *center*, *sides*, *grid*, \\*\\**kwargs* ):\n\n    Create a grid of *sites* each of which will be mosaiced separately and\n    then combined. Each of *center*, *sides*, and *grid* should be array-like\n    and of length two. *center* should be the very center location for the\n    mosaic in right ascension and declination (both in decimal degrees),\n    respectively. *sides* needs to give the side lengths of the desired\n    mosaic in decimal degrees (width-RA, height-DEC). *grid* should be the\n    grid division for the field (e.g., (2, 2) means 2x2 grid).\n\n    There will be a directory created for each *site* and also another *master*\n    directory. The final resulting mosaic will be deposited at\n    *final/mosaic.fits* here.\n\n    | Options   | Defaults | Descriptions                             |\n    |-----------|----------|------------------------------------------|\n    | *verbose* | True     | display messages, progress               |\n    | *survey*  | 'DSS'    | DSS, SDSS, 2MASS                         |\n    | *band*    | 'DSS2B'  | filter for *survey*, see *bands* dict    |\n    | *pad*     | 0.0      | amount to add (degrees) around *sites*   |\n\n    \u003cbr\u003e\n    The available filter band for each survey are as follows\n\n    | Survey  | Bands                                                   |\n    |---------|---------------------------------------------------------|\n    | '2MASS' | 'J', 'H', 'K'                                           |\n    | 'SDSS'  | 'U', 'G', 'R', 'I', 'Z'                                 |\n    | 'DSS'   | 'DSS1B', 'DSS1R', 'DSS2B', 'DSS2R', 'DSS2IR', 'Quick-V' |\n\n    \u003cbr\u003e\n    The user should execute the following available methods in this order:\n\n    - *ArchiveList* ( \\*\\**kwargs* ):\n\n        Run the `mArchiveList` command on the *site* grid. The only keyword\n        argument is *verbose* which defaults to True.\n\n    - *ArchiveExec* ( \\*\\**kwargs* ):\n\n        Run `mArchiveExec` on each *site* in the SubField. The only keyword\n        argument is *verbose* which defaults to True.\n\n    - *Build* ( *resolution*, \\*\\**kwargs*):\n\n        Run the build process for the *sites* in this SubField. See the\n        Montage.Mosaic() function documentation.\n\n    - *Collect* ( \\*\\**kwargs* ):\n\n        Collect the mosaics from all *site* locations into a master *images*\n        folder. The only keyword argument is *verbose* which defaults to True.\n\n    - *Merge* ( *resolution*, \\*\\**kwargs* ):\n\n        Merge all *site* mosaics into a single master SubField mosaic. We are\n        now calling Montage.Mosaic() on each *site*.\n\n    \u003cbr\u003e\n    **Example:**\n    ```python\n    from slipy import Montage, Simbad\n\n    # initialize the mosaic with a location, size, grid\n    mosaic = Montage.SubField(\n\n        Simbad.Position('Pleiades'), # center of the Pleiades\n        (4, 4),                      # side lengths of mosaic\n        (2, 2),                      # grid pattern creates 2x2 degree `sites`\n        band = 'DSS2B'               # Blue filter\n    )\n\n    # run mArchiveList to get the raw image tables\n    mosaic.ArchiveList()\n\n    # download the images at all `sites`\n    mosaic.ArchiveExec()\n\n    # run Montage.Mosaic() at each site, create a 4MP image,\n    # Notice: this creates \u003e 12 GB on disk!\n    mosaic.Build(3/2000, bkmodel=False)\n\n    # copy `site` mosaics to master image directory\n    mosaic.Collect()\n\n    # run Montage.Mosaic() on `site` mosaics\n    mosaic.Merge(3/2000, bkmodel=False)\n\n    # If you have APLpy\n    import aplpy\n    fig = aplpy.FITSFigure('master/final/mosaic.fits')\n    fig.show_grayscale()\n    fig.set_frame_color('gray')\n    fig.set_frame_linewidth(0.5)\n    fig.set_nan_color('black')\n    fig.set_tick_labels_xformat('hh:mm')\n    fig.set_tick_labels_yformat('dd:mm')\n\n    from matplotlib import pyplot as plt\n    plt.rc('text', usetex=True)\n    plt.rc('font', family='serif')\n    plt.draw()\n\n    fig.save('Pleiades.png')\n    ```\n\n    ![example](Figures/Pleiades.png)\n\n    **Figure 5:** Pleiades.png from the above code snippet.\n\n\u003ca name=MFieldLoc\u003e\u003c/a\u003e\n- class **Field** (*center*, *sides*, *grid*, *subgrid*, \\*\\**kwargs* ):\n\n    Large image mosaic manager for Montage. This class (in terms of its\n    usage) is the same as the *SubField* class, except that here we managing\n    the subfields. So all the member functions are the same name and purpose,\n    but instead act to call that same function on each subfield. Here, all\n    the constructor arguments are as before, with the additions of *subgrid*\n    which is also to be array-like of length two. *grid* will be the first\n    level division to find the centers and side lengths of all the subfields\n    and *subgrid* will be the further sub-division passed down to the daughter\n    subfields.\n\n    | Options   | Defaults | Descriptions                             |\n    |-----------|----------|------------------------------------------|\n    | *verbose* | True     | display messages, progress               |\n    | *survey*  | 'DSS'    | DSS, SDSS, 2MASS                         |\n    | *band*    | 'DSS2B'  | filter for *survey*, see *bands* dict    |\n    | *pad*     | 0.0      | amount to add (degrees) around *sites*   |\n\n    \u003cbr\u003e\n    The available filter band for each survey are as follows\n\n    | Survey  | Bands                                                   |\n    |---------|---------------------------------------------------------|\n    | '2MASS' | 'J', 'H', 'K'                                           |\n    | 'SDSS'  | 'U', 'G', 'R', 'I', 'Z'                                 |\n    | 'DSS'   | 'DSS1B', 'DSS1R', 'DSS2B', 'DSS2R', 'DSS2IR', 'Quick-V' |\n\n    \u003cbr\u003e\n    All the member functions are the same name as in *SubField*, but now with\n    the addition of a final step:\n\n    - *Finalize* ( *resolution*, \\*\\**kwargs* ):\n\n        Collect all SubField/master mosaics into a single folder and\n        run Mosaic() on them for a single final image.\n\n\n\u003cbr\u003e\n\u003ca name=ElodieLoc\u003e\u003c/a\u003e\n\n[Elodie](Data/Elodie.py)\n------------------------\n\nMethods for data retrieval from the Elodie Archive.\n\n\u003ca name=EArchiveLoc\u003e\u003c/a\u003e\n- class **Archive** ( \\*\\**kwargs* ):\n\n    Import and parse ascii catalog of Elodie archive files. The complete\n    archive is stored in the member dictionary, *data*. It's organized\n    by unique target names. Each target has a list of pairs consisting of the\n\tname of the file and the signal to noise for that spectrum. The reduced\n    archive by default contains only *HD*, *BD*, *HR*, *GC*, and *GJ* objects,\n    choosing the file pertaining to the spectra with the highest signal-to-noise\n    ratio available.\n\n    | Options    | Defaults                   | Descriptions          |\n    |------------|----------------------------|-----------------------|\n    | *infile*   | archives/elodie.csv        | path to input file    |\n    | *catalogs* | ['HD','BD','HR','GC','GJ'] | catalogs to keep      |\n\n    \u003cbr\u003e\n    **Example:**\n    ```python\n    from slipy.Data import Elodie\n\n    archive = Elodie.Archive()\n\n    'HD187642' in archive.files # returns True (Altair)\n    'HD045348' in archive.files # returns False (Canopus)\n    ```\n\n\u003ca name=EScriptLoc\u003e\u003c/a\u003e\n- **Script** ( *filename*, *pipeline* = '' ):\n\n    Construct url script for Elodie archive given *filename* and optionally\n    *pipeline* instructions (e.g., '\u0026z=wrs|fca[1,nor]').\n\n\u003ca name=EDownloadLoc\u003e\u003c/a\u003e\n- **Download** ( \\**files*, \\*\\**kwargs* ):\n\n    Download *files* from Elodie archive via url scripts. The spectra can be\n    further reduced via Elodie's pipeline with the following options.\n\n    | Options     | Defaults        | Descriptions                         |\n    |-------------|-----------------|--------------------------------------|\n    | *verbose*   | True            | display messages, progress           |\n    | *resample*  | (min, max, res) | resample spectra (no default)        |\n    | *normalize* | True            | continuum normalization              |\n    | *outpath*   | './'            | directory for downloaded *files*     |\n    | *names*     | []              | alternative output names for *files* |\n\n    \u003cbr\u003e\n    **Example:**\n    ```python\n\t# continuing from the previous example ...\n\n    # all files in the archive for Altair (file name is first element in pair)\n    files = [ entry[0] for entry in archive.data['HD187642'] ]\n\n    # download files to current directory, resample spectrum to wavelengths\n    # between 5850 and 5950 with a resolution of 0.01 Angstroms per pixel\n    Elodie.Download( *files, resample=(5850, 5950, 0.01) )\n    ```\n\n\u003cbr\u003e\n\u003ca name=AtomicLoc\u003e\u003c/a\u003e\n\n[Atomic](Data/Atomic.py)\n------------------------\n\nConvenient access to a large set of published atomic data for absorption lines:\n\n\"Atomic data for resonance absorption lines. III. Wavelengths longward\nof the Lyman limit for the elements Hydrogen to Gallium\"\u003cbr\u003e\nAuthor: Donald C. Morton (2003)\u003cbr\u003e\nOnline: http://iopscience.iop.org/0067-0049/149/1/205/fulltext/\n\n\u003ca name=IonManagerLoc\u003e\u003c/a\u003e\n- class **IonManager** ():\n\n    Managing class for the atomic data (Morton 2003). See SLiPy.Data.Archives.AtomicData.\n\n    - *\\_\\_call\\_\\_* ( *key*, \\*\\**kwargs* ):\n\n        Retrieve data from the Archives.AtomicData table. If the *key* is a string\n        type it is expected to be the name of an ion (e.g., 'C III'). If the *key* is\n        a number it is expected to be a wavelength value (if not with units Angstroms are\n        implied). The default is *vacuum* wavelength, but *air* can be specified with the\n        keyword argument `wavelength='Air'`.\n\n        If the key was the name of an ion, all the lines for that ion are returned. If the\n        key was a wavelength, the closest line in the table to that wavelength is returned.\n        You can request a wavelength range by giving the *key* as a tuple of two wavelengths\n        specifying the range.\n\n        The results default to the f-value (a.k.a. the oscillator strength) but can be\n        changed with the keyword argument *lookup*. Options include, *air*, *vacuum*, *ion*,\n        *elow*, *logwf*, and *fvalue*.\n\n        The return is either a single pair or a list of pairs: the first element of each pair\n        is always a wavelength value (in air if wavelength='air' or in vacuum otherwise), the\n        second being the entries requested. The wavelength type is always that used for\n        the look-up. That is, Vacuum by default, but if `wavelength='Air'` is given, the\n        returns will be in air wavelengths. Be aware that *None* might be returned if\n        there is not Air wavelength for the line. Further, all results will be returned\n        as *None* where no data is available.\n\n        | Options      | Defaults  | Alternatives                            |\n        |--------------|-----------|-----------------------------------------|\n        | *wavelength* | 'vacuum'  | 'air'                                   |\n        | *lookup*     | 'fvalue'  | 'air', 'vacuum', 'ion', 'elow', 'logwf' |\n\n    The *IonManager* can be imported via the member instance *IonSearch*.\n\n    **Examples:**\n\n    Import the data set:\n    ```python\n    from slipy.Data.Atomic import IonSearch\n    # equivalent to `from slipy.Data.Atomic import IonManager; IonSearch = IonManager()`\n    ```\n\n    The member *.data* contains the entire table from Morton 2003. We can access information\n    of interest directly however by calling the *Ions* object.\n    ```python\n    IonSearch('C III')\n    ```\n    ```\n    [(\u003cQuantity 977.0201 Angstrom\u003e, 0.7570010842747638),\n     (\u003cQuantity 1908.734 Angstrom\u003e, 1.6875419997146983e-07)]\n    ```\n\n    The second item in each of those pairs was the oscillator strength, or *fvalue*, for the\n    lines. The wavelength given was in *vacuum*. We can request the same lines in *air*:\n    ```python\n    IonSearch('C III', wavelength='air')\n    ```\n    ```\n    [(None, 0.7570010842747638), (None, 1.6875419997146983e-07)]\n    ```\n\n    The result is *None* because those values don't exist in the data set. But they are indeed\n    the same lines.\n\n    We can ask for a wavelength range, and change what we are looking up:\n    ```python\n    IonSearch( (5885, 5900), wavelength='air', lookup='ion')\n    ```\n    ```\n    [(\u003cQuantity 5889.951 Angstrom\u003e, 'Na I'),\n     (\u003cQuantity 5894.092 Angstrom\u003e, 'Ti I'),\n     (\u003cQuantity 5895.924 Angstrom\u003e, 'Na I')]\n    ```\n\n    Units work as well:\n    ```python\n    from astropy import units as u\n    IonSearch( (588.5 * u.nm, 590.0 * u.nm), wavelength='air', lookup='ion')\n    ```\n    ```\n    [(\u003cQuantity 5889.951 Angstrom\u003e, 'Na I'),\n     (\u003cQuantity 5894.092 Angstrom\u003e, 'Ti I'),\n     (\u003cQuantity 5895.924 Angstrom\u003e, 'Na I')]\n    ```\n\n\u003cbr\u003e\n\u003ca name=IonLoc\u003e\u003c/a\u003e\n- class **Ion** ( *name* = None, *wavelength* = None, *fvalue* = None, *A* = None, \\*\\**kwargs*):\n\n    An object for declaring atomic ions.\n\n    An *Ion* should have a name, wavelength (air or vacuum), osciallator strength,\n    and a transition probability (Einstein coefficient).\n\n    Much of this data is available from the ..Data.Archives.AtomicData module searchable\n    with the ..Data.Atomic.IonManager class. In the future, we hope to implement an\n    internal database of transition probabilities for each ion in the AtomicData module\n    from the Morton 2003 publication. Currently, the user must provide this data.\n\n    The NIST Atomic Spectra Database Lines Data is a good source for atomic data values:\n    http://physics.nist.gov/PhysRefData/ASD/lines_form.html\n\n    If no arguments are given the state remains uninitialized.\n    The *name* (e.g., 'C III') is used to connect with the data in the\n    ..Data.Archives.AtomicData module via the IonManager class. The *wavelength* need\n    not necessarily be the exact value of the line; the line closest to that given\n    for the named ion is used. This is by default the wavelength in vacuum, but can\n    be the wavelength in air if the keyword argument `medium='air'` is given.\n    The created member attribute wavelength* and *fvalue* are automatically assigned\n    based on this procedure, but can be explicitly assigned if the *fvalue* is\n    provided directly. The transition probability (Einstein coefficient) *A* is simply\n    attached as *A*. If no units are given for *A*, *per second* is assigned.\n\n    *Example:*\n    ```python\n    from slipy.Data import Atomic\n    D2 = Atomic.Ion('Na I', 589.1 * u.nm, A = 6.16e7 / u.s)\n    D2\n    ```\n    ```\n    Ion:        Na I\n    Wavelength: 589.1583300000001 nm\n    fvalue:     0.6408671009122726\n    A:          61600000.0 1 / s\n    ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglentner%2Fslipy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglentner%2Fslipy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglentner%2Fslipy/lists"}