Package: skymapper
SkymapperA collection of matplotlib instructions to map astronomical survey data from the celestial sphere onto 2D.The purpose of this package is to facilitate interactive work as well as the the creation of publication-quality plots with a python-based workflow many astronomers are accustomed to. The primary motivation is a truthful representation of samples and fields from the curved sky in planar figures, which becomes relevant when sizable portions of the sky are observed.What can it do? For instance, find the optimal projection for a given list of spherical coordinates andcreating a density mapfrom a catalog in a few lines:importskymapperasskm# 1) construct a projection, here Albers# lon_0, lat_0: longitude/latitude that map onto 0/0# lat_1, lat_2: reference latitudes for conic projectionlon_0,lat_0,lat_1,lat_2=27.35,-37.04,-57.06,-11.34proj=skm.Albers(lon_0,lat_0,lat_1,lat_2)# alternative: define the optimal projection for set of coordinates# by minimizing the variation in distortioncrit=skm.stdDistortionproj=skm.Albers.optimize(ra,dec,crit=crit)# 2) construct map: will hold figure and projection# the outline of the sphere can be styled with kwargs for matplotlib Polygonmap=skm.Map(proj)# 3) add graticules, separated by 15 deg# the lines can be styled with kwargs for matplotlib Line2D# additional arguments for formatting the graticule labelssep=15map.grid(sep=sep)# 4) add data to the map, e.g.# make density plotnside=32mappable=map.density(ra,dec,nside=nside)cb=map.colorbar(mappable,cb_label="$n_g$ [arcmin$^{-2}$]")# add scatter plotmap.scatter(ra_scatter,dec_scatter,s=size_scatter,edgecolor='k',facecolor='None')# focus on relevant regionmap.focus(ra,dec)Themapinstance has several members, most notablyfig: thematplotlib.Figurethat holds the mapax: thematplotlib.Axesthat holds the mapThe syntax mimicsmatplotlibas closely as possible. Currently supported are canonical plotting functionsplotscatterhexbinfor binning and interpolating samplescolorbarwith an optional argumentcb_labelto set the labeltextwith an optionaldirection in ['parallel','meridian']argument to align along either graticuleas well as special functionsfootprintto show the region covered by a surveyvertexto plot a list of simple convex polygonshealpixto plot a healpix map as a list of polygonsdensityto create a density map in healpix cellsextrapolateto generate a field from samples over the entire sky or a subregionExploratory and interactive workflows are specifically supported. For instance, you can zoom and pan, also scroll in/out (google-maps style), and themapwill automatically update the location of the graticule labels, which are not regularly spaced.The styling of graticules can be changed by callingmap.grid()with different parameters. Finer-grained access is provided bymap.labelParallelsAtFrame()creates/styles the vertical axis labels at the intersection of the grid parallelsmap.labelMeridiansAtFrame()creates/styles the horizontal axis labels at the intersection of the grid meridiansmap.labelParallelsAtMeridian()creates/styles parallels at a given meridian (useful for all-sky maps)map.labelMeridiansAtParallel()creates/styles meridians at a given parallel (useful for all-sky maps)Installation and PrerequisitesYou can either clone the repo and install bypython setup.py installor get the latest release withpip install skymapperDependencies:numpyscipymatplotlibhealpyFor survey footprints, you'll needpymangle.BackgroundThe essential parts of the workflow areCreating theProjection, e.g.Hammer,Albers,WagnerIVSetting up aMapto hold the projection and matplotlib figure, ax, ...Add data to the mapSeveral map projections are available, the full list is stored in the dictionaryprojection_register. If the projection you want isn't included, open an issue, or better: create it yourself (see below) and submit a pull request.There are two conventions for longitudes in astronomy. The standard frame, used for instance for world maps or Galactic maps, has a longitudinal coordinates in the range [-180 .. 180] deg, which increase west to east (in other words, on the map east is right). The equatorial (RA/Dec) frame is left-handed (i.e. on the map east is left) and has coordinates in the range [0 .. 360] deg. To determine the convention,Projectionhas an argumentlon_type, which can be either"lon"or"ra"for standard or equatorial, respectively. The default islon_type="ra".Map projections can preserve sky area, angles, or distances, but never all three. That means defining a suitable projection must be a compromise. For most applications, sizes should exactly be preserved, which means that angles and distances may not be. The optimal projection for a given list ofra,deccan be found by calling:crit=skm.projection.stdDistortionproj=skm.Albers.optimize(ra,dec,crit=crit)This optimizes theAlbersprojection parameters to minimize the variance of the map distortion (i.e. the apparent ellipticity of a true circle on the sky). Alternative criteria are e.g.maxDistortionorstdScale(for projections that are not equal-area).Creating a custom projectionFor constructing your own projection, derive fromProjection. You'll see that every projection needs to implement at least these methods:transformto map from spherical to map coordinates x/yinvertto map from x/y to spherical (if not implemented defaults to basic and slow BFGS inversion)If the projection has several parameters, you will want to create a special@classmethod optimizebecause the default one only determines the best longitude reference. An example for that is given in e.g.ConicProjection.optimize.Creating/using a surveySeveral surveys are predefined and listed in thesurvey_registerdictionary. If the survey you want isn't included, don't despair. To create one can derive a class fromSurvey, which only needs to implement one method:​def contains(self, ra, dec)to determine whether RA, Dec are inside the footprint.If this looks like thepymangleinterface: it should. That means that you can avoid the overhead of having to define a survey and e.g. pass apymangle.Mangleobject directly tofootprint().Limitation(s)The combination ofMapandProjectionisnotamatplotlib transformation. Among several reasons, it is very difficult (maybe impossible) to work with thematplotlib.Axesthat are not rectangles or ellipses. So, we decided to split the problem: making use of matplotlib for lower-level graphics primitive and layering the map-making on top of it. This way, we can control e.g. the interpolation method on the sphere or the location of the tick labels in a way consistent with visual expectations from hundreds of years of cartography. Whileskymappertries to follow matplotlib conventions very closely, some methods may not work as expected. Open an issue if you think you found such a case.In particular, we'd appreciate help to make sure that the interactive features work well on all matplotlib backends.