1

I need to make a contour plot and overlie the contours on the image. I have used aplpy library to overlie the contours on an astronomical image. I have downloaded the 2MASS data in APlpy website(https://github.com/aplpy/aplpy-examples/tree/master/data) and wrote the following piece of code:

import numpy as np
import aplpy
import atpy
from pyavm import AVM
import scipy
import matplotlib.pyplot as plt
import scipy.ndimage
from matplotlib import cm
import montage_wrapper
import matplotlib.colors as colors
from scipy import stats

def get_contour_verts(cn):
    contours = []
    # for each contour line
    for cc in cn.collections:
        paths = []
        # for each separate section of the contour line
        for pp in cc.get_paths():
            xy = []
            # for each segment of that section
            for vv in pp.iter_segments():
                xy.append(vv[0])
            paths.append(np.vstack(xy))
        contours.append(paths)
    return contours

# Convert all images to common projection
aplpy.make_rgb_cube(['2MASS_h.fits', '2MASS_j.fits', '2MASS_k.fits'], '2MASS_rgb.fits')

# Customize it
aplpy.make_rgb_image('2MASS_rgb.fits','2MASS_rgb_contour.png',embed_avm_tags=True)

# Launch APLpy figure of 2D cube
img = aplpy.FITSFigure('2MASS_rgb_contour.png')
img.show_rgb()

# Modify the tick labels for precision and format
img.tick_labels.set_xformat('hhmm')
img.tick_labels.set_yformat('ddmm')
# Move the tick labels
img.tick_labels.set_xposition('top')
img.tick_labels.set_yposition('right')
img.tick_labels.set_font(size='small', family='sans-serif', style='normal')

data = scipy.loadtxt('sources.txt')
m1=data[:,0]
m2=data[:,1]
xmin = m1.min()
xmax = m1.max()
ymin = m2.min()
ymax = m2.max()
#Gridding the data 

X, Y = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
positions = np.vstack([X.ravel(), Y.ravel()])
values = np.vstack([m1, m2])
kernel = stats.gaussian_kde(values)
Z = np.reshape(kernel(positions).T, X.shape)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(np.rot90(Z), cmap=plt.cm.gist_earth_r, extent=[xmin, xmax, ymin, ymax])
ax.plot(m1, m2, 'k.', markersize=2)
ax.set_xlim([xmin, xmax])
ax.set_ylim([ymin, ymax])

CS = plt.contour(X, Y, Z)
Contour_arrays=get_contour_verts(CS)

#Adding contour plots
for contours_at_level in Contour_arrays:
    radec = [img.pixel2world(*verts.T) for verts in contours_at_level]
    new_radec=[]
    for coor in radec:
        #new_radec.append(np.column_stack((coor[0], coor[1])))
        new_radec.append(np.vstack((coor[0], coor[1])))
    print new_radec
    img.show_lines(new_radec,color='red', zorder=100)

img.save('tutorial.png')

It seems it does not still work at all.

Dalek
  • 4,168
  • 11
  • 48
  • 100
  • About making contour plots with matplotlib you have plenty of examples around StackOverflow. Now, if you want to save the plot as a FITS file you need first to convert the plot to a numpy array (eg., following the process described [here](http://www.icare.univ-lille1.fr/wiki/index.php/How_to_convert_a_matplotlib_figure_to_a_numpy_array_or_a_PIL_image)), and then use PyFITS to create a FITS file with the array. – Ricardo Cárdenes Feb 07 '14 at 19:50
  • @RicardoCárdenes How could I transfer the information from right ascension and declination coordinates, when I convert matplotlib contour plot to an array? – Dalek Feb 07 '14 at 22:38
  • @Dalek - change your loop to match my edited one. I had made a mistake; the contours you created are *already* in ra/dec coordinates, so you don't need to do the pixel->world transformation. Note that the linked example (github.com/aplpy/aplpy-examples/pull/1) has the correct version – keflavich Feb 12 '14 at 06:50

1 Answers1

2

You can't "save contours as a FITS file" directly, but there are other approaches you can try.

You can use the matplotlib._cntr tool as described here: Python: find contour lines from matplotlib.pyplot.contour() to get the endpoints in figure coordinates, then use the WCS to convert between pixel and world coordinates. aplpy.FITSFigures have convenience functions, F.world2pixel and F.pixel2world, which each accept 2 arrays:

F.pixel2world(arange(5),arange(5))

So if you are working with a grid that is identical to that shown in the FITSFigure window, you could convert your points to world coordinates and plot them with show_lines:

ra,dec = F.pixel2world(xpix,ypix)
F.show_lines([[ra,dec]])

or for a more realistic contour case, now copying the code from the linked article:

import numpy as np
import aplpy

def get_contour_verts(cn):
    contours = []
    # for each contour line
    for cc in cn.collections:
        paths = []
        # for each separate section of the contour line
        for pp in cc.get_paths():
            xy = []
            # for each segment of that section
            for vv in pp.iter_segments():
                xy.append(vv[0])
            paths.append(np.vstack(xy))
        contours.append(paths)

    return contours

# This line is copied from the question's code, and assumes that has been run previously
CS = plt.contour(Xgrid, Ygrid, Hsmooth,levels=loglvl,extent=extent,norm=LogNorm())

contours = get_contour_verts(CS) # use the linked code


gc = aplpy.FITSFigure('2MASS.fits',figsize=(10,9))

# each level comes with a different set of vertices, so you have to loop over them
for contours_at_level in Contour_arrays:
    clines = [cl.T for cl in contours_at_level]
    img.show_lines(clines,color='red', zorder=100)

Still the simplest approach is, if you have a FITS file from which you're generating said contours, just use that file directly. Or if you don't have a FITS file, you can make one with pyfits by creating your own header.

Community
  • 1
  • 1
keflavich
  • 18,278
  • 20
  • 86
  • 118
  • could you please elaborate more how I could use WCS(is it from astropy) in order to convert the gridded data at contour plot to WCS? – Dalek Feb 07 '14 at 23:54
  • Dalek: detailed answer added – keflavich Feb 08 '14 at 07:42
  • it is still very vague for me, how I should implement it. if I use c = cntr.Cntr(Xgrid, Ygrid, Hsmooth) then c.get_cdata() gives me a (nx,ny) array but it is the amount of each grid point and on the other hand c.trace(z) a list of points in the contour which are in ra and dec coordinate. Which one should be convert to fits file and could you explain a bit more which one can be read by show_contour() in aplpy.FITSFigure()? Thanks – Dalek Feb 08 '14 at 18:46
  • You can't use `show_contour` for this purpose, you need to use `show_lines` instead. I've updated the example to be explicit for the case you outlined in the question – keflavich Feb 09 '14 at 11:21
  • I got this error message when I ran the last loop written in your answer: ERROR: TypeError: pixel2world() takes exactly 3 arguments (2 given) [IPython.core.interactiveshell] Isn't pixel2world() supposed to get just x and y coordinates? – Dalek Feb 09 '14 at 19:40
  • Yes, but it also takes `self`. It should be `gc.pixel2world(*verts.T)` – keflavich Feb 10 '14 at 05:41
  • Thanks! I face new problem running line by line. Sorry I post too much. I got this error message for the last line of the code:`----> 3 img.show_lines(radec) 1256 for line in line_list: -> 1257 xp, yp = wcs_util.world2pix(self._wcs, line[0, :], line[1, :]) 1258 lines.append(np.column_stack((xp, yp))) 1259 TypeError: list indices must be integers, not tuple` – Dalek Feb 10 '14 at 12:25
  • It is getting really frustrating because I don't get any error message but at the end it doesn't plot contours! – Dalek Feb 10 '14 at 19:20
  • Quick sanity check: Are all of those ra,dec coordinates in your image? If so, try playing with the `zorder` keyword: set `zorder=100`, for example. – keflavich Feb 11 '14 at 06:02
  • It still doesn't show the contours! Is there any other sanity check to assure that the function got the right inputs and is able to plot? Or can you post an example here or in aplpy webpage? – Dalek Feb 11 '14 at 12:25
  • Dalek: Looks like this might be a bug! Add `color='r'` and they should show up. See this new example: https://github.com/aplpy/aplpy-examples/pull/1 – keflavich Feb 11 '14 at 13:38
  • I modified my question but putting together pieces from your replies and posted again as original question! Could you take a look and clarify for me where I have done mistakes in order to make contour plots? – Dalek Feb 11 '14 at 23:10
  • I am trying to use my old code and modify it a bit and add something similar to `clabel(clines[3:], inline=1, fontsize=20., fmt=ticker.LogFormatterMathtext())` in `matplotlib` for `aplpy`, but it doesn't work, do you have any idea how I could make it work! Thanks in advance~ – Dalek Oct 10 '14 at 09:52