def reflectance_correction(rad_arr, lons, lats): '''Make satpy "reflectances" consistent with usual definition Reflectance is normally defined as outgoing radiation/incoming radiation. In satpy, the denominator is set to a fixed value - the incoming radiation for a solar zenith angle of 0 and earth-sun distance of one. This function corrects this using the actual earth-sun distance and the solar zenith angle appropriate for the observation time. See discussion at https://github.com/pytroll/satpy/issues/536 for further details. Args: rad_arr (Xarray): Xarray for one of the two visible channels (0.6, 0.8) from satpy scene lons (ndarray, shape(nlat,nlon)): Array of longitude values lats (ndarray, shape(nlat,nlon)): Array of longitude values Returns: rad_arr (Xarray): Input array, with reflectance corrected to account for solar zenith angle and earth-sun distance. ''' from astropy.units import AU # Requires virtual environment from sunpy.sun import sunearth_distance # Requires virtual environment from pyorbital.astronomy import sun_zenith_angle nx = rad_arr.sizes['x'] ny = rad_arr.sizes['y'] mu0 = np.ma.zeros((ny,nx)) dist_sun_earth = np.ma.zeros(ny) Tacq = rad_arr.attrs["end_time"] - rad_arr.attrs["start_time"] for j in range(ny) : tacq = rad_arr.attrs["start_time"] + datetime.timedelta( seconds=(j/float(ny))*Tacq.seconds ) mu0[j,:] = np.ma.masked_outside( np.pi*sun_zenith_angle( tacq, lons[j,:], lats[j,:])/180.,0.035, 1, copy=False) # in degrees dist_sun_earth[j] = float(sunearth_distance(tacq) / AU) rad_arr.values *= ((dist_sun_earth[:,None]**2) / np.cos(mu0)) # sun earth distance in AU. return rad_arr
def test_sunearth_distance(): assert_array_almost_equal(sun.sunearth_distance("2010/02/04"), 0.9858, decimal=4) assert_array_almost_equal(sun.sunearth_distance("2009/04/13"), 1.003, decimal=4) assert_array_almost_equal(sun.sunearth_distance("2008/06/20"), 1.016, decimal=4) assert_array_almost_equal(sun.sunearth_distance("2007/08/15"), 1.013, decimal=4) assert_array_almost_equal(sun.sunearth_distance("2007/10/02"), 1.001, decimal=4) assert_array_almost_equal(sun.sunearth_distance("2006/12/27"), 0.9834, decimal=4)
def test(): """ Print out a summary of Solar ephemeris A correct answer set to compare to Solar Ephemeris for 1-JAN-01 00:00:00 Distance (AU) = 0.98330468 Semidiameter (arc sec) = 975.92336 True (long, lat) in degrees = (280.64366, 0.00000) Apparent (long, lat) in degrees = (280.63336, 0.00000) True (RA, Dec) in hrs, deg = (18.771741, -23.012449) Apparent (RA, Dec) in hrs, deg = (18.770994, -23.012593) Heliographic long. and lat. of disk center in deg = (217.31269, -3.0416292) Position angle of north pole in deg = 2.0102649 Carrington Rotation Number = 1971.4091 check! """ t = '2001-01-01T00:00:00' swpy_jd = swdt.julian_day(t) sunpy_jd = sunt.julian_day(t) print "SWPY JD: {}, SUNPY JD: {}".format(swpy_jd,sunpy_jd) print "Sun-earth distance: {}, {}".format( sun.sunearth_distance(t), ssun.sunearth_distance(t)) print "Solar semidiameter angular size: {}, {}".format( sun.solar_semidiameter_angular_size(t), sun.solar_semidiameter_angular_size(t)) print "True longitude: {}, {}".format(sun.true_longitude(t), ssun.true_longitude(t)) print "Apparent Longitude: {}, {}".format(sun.apparent_longitude(t), ssun.apparent_longitude(t)) print "True R.A.: {}, {}".format( sun.true_rightascension(t), ssun.true_rightascension(t)) print "True Dec.: {}, {}".format(sun.true_declination(t), ssun.true_declination(t)) print "Apparent R.A.: {}, {}".format( sun.apparent_rightascension(t), ssun.apparent_rightascension(t)) print "Apparent Dec.: {}, {}".format(sun.apparent_declination(t), ssun.apparent_declination(t)) print "Heliographic center: {}, {}".format(sun.heliographic_solar_center(t), ssun.heliographic_solar_center(t)) print "Position angle of north pole [deg]: {}, {}".format(sun.solar_north(t), ssun.solar_north(t)) print "Carrington rotation number: {}, {}".format(sun.carrington_rotation_number(t), ssun.carrington_rotation_number(t))
def plt_qlook_image(imres, figdir=None, verbose=True, synoptic=False): from matplotlib import pyplot as plt from sunpy import map as smap from sunpy import sun from matplotlib import colors import astropy.units as u from suncasa.utils import plot_mapX as pmX # from matplotlib import gridspec as gridspec if not figdir: figdir = './' nspw = len(set(imres['Spw'])) plttimes = list(set(imres['BeginTime'])) ntime = len(plttimes) # sort the imres according to time images = np.array(imres['ImageName']) btimes = Time(imres['BeginTime']) etimes = Time(imres['EndTime']) spws = np.array(imres['Spw']) suc = np.array(imres['Succeeded']) inds = btimes.argsort() images_sort = images[inds].reshape(ntime, nspw) btimes_sort = btimes[inds].reshape(ntime, nspw) suc_sort = suc[inds].reshape(ntime, nspw) if verbose: print('{0:d} figures to plot'.format(ntime)) plt.ioff() fig = plt.figure(figsize=(8, 8)) plt.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0) axs = [] ims = [] pltst = 0 for i in range(ntime): plt.ioff() plttime = btimes_sort[i, 0] tofd = plttime.mjd - np.fix(plttime.mjd) suci = suc_sort[i] if not synoptic: if tofd < 16. / 24. or sum( suci ) < nspw - 2: # if time of the day is before 16 UT (and 24 UT), skip plotting (because the old antennas are not tracking) continue else: if pltst == 0: i0 = i pltst = 1 else: if pltst == 0: i0 = i pltst = 1 if i == i0: if synoptic: timetext = fig.text(0.01, 0.98, plttime.iso[:10], color='w', fontweight='bold', fontsize=12, ha='left') else: timetext = fig.text(0.01, 0.98, plttime.iso[:19], color='w', fontweight='bold', fontsize=12, ha='left') else: if synoptic: timetext.set_text(plttime.iso[:10]) else: timetext.set_text(plttime.iso[:19]) if verbose: print('Plotting image at: ', plttime.iso) for n in range(nspw): plt.ioff() if i == i0: if nspw == 1: ax = fig.add_subplot(111) else: ax = fig.add_subplot(nspw / 2, 2, n + 1) axs.append(ax) else: ax = axs[n] image = images_sort[i, n] if suci[n] or os.path.exists(image): try: eomap = smap.Map(image) except: continue data = eomap.data sz = data.shape if len(sz) == 4: data = data.reshape((sz[2], sz[3])) data[np.isnan(data)] = 0.0 # add a basin flux to the image to avoid negative values data = data + 0.8e5 data[data < 0] = 0.0 data = np.sqrt(data) eomap = smap.Map(data, eomap.meta) # resample the image for plotting dim = u.Quantity([256, 256], u.pixel) eomap = eomap.resample(dim) else: # make an empty map data = np.zeros((256, 256)) header = { "DATE-OBS": plttime.isot, "EXPTIME": 0., "CDELT1": 10., "NAXIS1": 256, "CRVAL1": 0., "CRPIX1": 128.5, "CUNIT1": "arcsec", "CTYPE1": "HPLN-TAN", "CDELT2": 10., "NAXIS2": 256, "CRVAL2": 0., "CRPIX2": 128.5, "CUNIT2": "arcsec", "CTYPE2": "HPLT-TAN", "HGLT_OBS": sun.heliographic_solar_center(plttime)[1].value, "HGLN_OBS": 0., "RSUN_OBS": sun.solar_semidiameter_angular_size(plttime).value, "RSUN_REF": sun.constants.radius.value, "DSUN_OBS": sun.sunearth_distance(plttime).to(u.meter).value, } eomap = smap.Map(data, header) if i == i0: eomap_ = pmX.Sunmap(eomap) # im = eomap_.imshow(axes=ax, cmap='jet', norm=colors.LogNorm(vmin=0.1, vmax=1e8)) im = eomap_.imshow(axes=ax, cmap='jet', norm=colors.Normalize(vmin=150, vmax=700)) ims.append(im) if not synoptic: eomap_.draw_limb(axes=ax) eomap_.draw_grid(axes=ax) ax.set_xlim([-1080, 1080]) ax.set_ylim([-1080, 1080]) try: cfreq = eomap.meta['crval3'] / 1.0e9 bdwid = eomap.meta['cdelt3'] / 1.0e9 ax.text(0.98, 0.01, '{0:.1f} - {1:.1f} GHz'.format( cfreq - bdwid / 2.0, cfreq + bdwid / 2.0), color='w', transform=ax.transAxes, fontweight='bold', ha='right') except: pass ax.set_title(' ') ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels(['']) ax.set_yticklabels(['']) else: ims[n].set_data(eomap.data) fig_tdt = plttime.to_datetime() if synoptic: fig_subdir = fig_tdt.strftime("%Y/") figname = 'eovsa_qlimg_' + plttime.iso[:10].replace('-', '') + '.png' else: fig_subdir = fig_tdt.strftime("%Y/%m/%d/") figname = 'eovsa_qlimg_' + plttime.isot.replace(':', '').replace( '-', '')[:15] + '.png' figdir_ = figdir + fig_subdir if not os.path.exists(figdir_): os.makedirs(figdir_) if verbose: print('Saving plot to :' + figdir_ + figname) plt.savefig(figdir_ + figname) plt.close(fig)
def imreg(vis=None, ephem=None, msinfo=None, imagefile=None, timerange=None, reftime=None, fitsfile=None, beamfile=None, offsetfile=None, toTb=None, sclfactor=1.0, verbose=False, p_ang=False, overwrite=True, usephacenter=True, deletehistory=False, subregion=[], docompress=False): ''' main routine to register CASA images Required Inputs: vis: STRING. CASA measurement set from which the image is derived imagefile: STRING or LIST. name of the input CASA image timerange: STRING or LIST. timerange used to generate the CASA image, must have the same length as the input images. Each element should be in CASA standard time format, e.g., '2012/03/03/12:00:00~2012/03/03/13:00:00' Optional Inputs: msinfo: DICTIONARY. CASA MS information, output from read_msinfo. If not provided, generate one from the supplied vis ephem: DICTIONARY. solar ephem, output from read_horizons. If not provided, query JPL Horizons based on time info of the vis (internet connection required) fitsfile: STRING or LIST. name of the output registered fits files reftime: STRING or LIST. Each element should be in CASA standard time format, e.g., '2012/03/03/12:00:00' offsetfile: optionally provide an offset with a series of solar x and y offsets with timestamps toTb: Bool. Convert the default Jy/beam to brightness temperature? sclfactor: scale the image values up by its value (to compensate VLA 20 dB attenuator) verbose: Bool. Show more diagnostic info if True. usephacenter: Bool -- if True, correct for the RA and DEC in the ms file based on solar empheris. Otherwise assume the phasecenter is correctly pointed to the solar disk center (EOVSA case) subregion: Region selection. See 'help par.region' for details. Usage: >>> from suncasa.utils import helioimage2fits as hf >>> hf.imreg(vis='mydata.ms', imagefile='myimage.image', fitsfile='myimage.fits', timerange='2017/08/21/20:21:10~2017/08/21/20:21:18') The output fits file is 'myimage.fits' History: BC (sometime in 2014): function was first wrote, followed by a number of edits by BC and SY BC (2019-07-16): Added checks for stokes parameter. Verified that for converting from Jy/beam to brightness temperature, the convention of 2*k_b*T should always be used. I.e., for unpolarized source, stokes I, RR, LL, XX, YY, etc. in the output CASA images from (t)clean should all have same values of radio intensity (in Jy/beam) and brightness temperature (in K). ''' if deletehistory: ms_clearhistory(vis) if not imagefile: raise ValueError('Please specify input image') if not timerange: raise ValueError('Please specify timerange of the input image') if type(imagefile) == str: imagefile = [imagefile] if type(timerange) == str: timerange = [timerange] if not fitsfile: fitsfile = [img + '.fits' for img in imagefile] if type(fitsfile) == str: fitsfile = [fitsfile] nimg = len(imagefile) if len(timerange) != nimg: raise ValueError( 'Number of input images does not equal to number of timeranges!') if len(fitsfile) != nimg: raise ValueError( 'Number of input images does not equal to number of output fits files!' ) nimg = len(imagefile) if verbose: print(str(nimg) + ' images to process...') if reftime: # use as reference time to find solar disk RA and DEC to register the image, but not the actual timerange associated with the image if type(reftime) == str: reftime = [reftime] * nimg if len(reftime) != nimg: raise ValueError( 'Number of reference times does not match that of input images!' ) helio = ephem_to_helio(vis, ephem=ephem, msinfo=msinfo, reftime=reftime, usephacenter=usephacenter) else: # use the supplied timerange to register the image helio = ephem_to_helio(vis, ephem=ephem, msinfo=msinfo, reftime=timerange, usephacenter=usephacenter) if toTb: (bmajs, bmins, bpas, beamunits, bpaunits) = getbeam(imagefile=imagefile, beamfile=beamfile) for n, img in enumerate(imagefile): if verbose: print('processing image #' + str(n) + ' ' + img) fitsf = fitsfile[n] timeran = timerange[n] # obtain duration of the image as FITS header exptime try: [tbg0, tend0] = timeran.split('~') tbg_d = qa.getvalue(qa.convert(qa.totime(tbg0), 'd'))[0] tend_d = qa.getvalue(qa.convert(qa.totime(tend0), 'd'))[0] tdur_s = (tend_d - tbg_d) * 3600. * 24. dateobs = qa.time(qa.quantity(tbg_d, 'd'), form='fits', prec=10)[0] except: print('Error in converting the input timerange: ' + str(timeran) + '. Proceeding to the next image...') continue hel = helio[n] if not os.path.exists(img): warnings.warn('{} does not existed!'.format(img)) else: if os.path.exists(fitsf) and not overwrite: raise ValueError( 'Specified fits file already exists and overwrite is set to False. Aborting...' ) else: p0 = hel['p0'] tb.open(img + '/logtable', nomodify=False) nobs = tb.nrows() tb.removerows([i + 1 for i in range(nobs - 1)]) tb.close() ia.open(img) imr = ia.rotate(pa=str(-p0) + 'deg') if subregion is not []: imr = imr.subimage(region=subregion) imr.tofits(fitsf, history=False, overwrite=overwrite) imr.close() imsum = ia.summary() ia.close() ia.done() # construct the standard fits header # RA and DEC of the reference pixel crpix1 and crpix2 (imra, imdec) = (imsum['refval'][0], imsum['refval'][1]) # find out the difference of the image center to the CASA phase center # RA and DEC difference in arcseconds ddec = degrees((imdec - hel['dec_fld'])) * 3600. dra = degrees((imra - hel['ra_fld']) * cos(hel['dec_fld'])) * 3600. # Convert into image heliocentric offsets prad = -radians(hel['p0']) dx = (-dra) * cos(prad) - ddec * sin(prad) dy = (-dra) * sin(prad) + ddec * cos(prad) if offsetfile: try: offset = np.load(offsetfile) except: raise ValueError( 'The specified offsetfile does not exist!') reftimes_d = offset['reftimes_d'] xoffs = offset['xoffs'] yoffs = offset['yoffs'] timg_d = hel['reftime'] ind = bisect.bisect_left(reftimes_d, timg_d) xoff = xoffs[ind - 1] yoff = yoffs[ind - 1] else: xoff = hel['refx'] yoff = hel['refy'] if verbose: print( 'offset of image phase center to visibility phase center (arcsec): dx={0:.2f}, dy={1:.2f}' .format(dx, dy)) print( 'offset of visibility phase center to solar disk center (arcsec): dx={0:.2f}, dy={1:.2f}' .format(xoff, yoff)) (crval1, crval2) = (xoff + dx, yoff + dy) # update the fits header to heliocentric coordinates hdu = pyfits.open(fitsf, mode='update') hdu[0].verify('fix') header = hdu[0].header dshape = hdu[0].data.shape ndim = hdu[0].data.ndim (cdelt1, cdelt2) = (-header['cdelt1'] * 3600., header['cdelt2'] * 3600. ) # Original CDELT1, 2 are for RA and DEC in degrees header['cdelt1'] = cdelt1 header['cdelt2'] = cdelt2 header['cunit1'] = 'arcsec' header['cunit2'] = 'arcsec' header['crval1'] = crval1 header['crval2'] = crval2 header['ctype1'] = 'HPLN-TAN' header['ctype2'] = 'HPLT-TAN' header['date-obs'] = dateobs # begin time of the image if not p_ang: hel['p0'] = 0 try: # this works for pyfits version of CASA 4.7.0 but not CASA 4.6.0 if tdur_s: header.set('exptime', tdur_s) else: header.set('exptime', 1.) header.set('p_angle', hel['p0']) header.set('hgln_obs', 0.) header.set('rsun_ref', sun.constants.radius.value) if sunpyver <= 1: header.set( 'dsun_obs', sun.sunearth_distance(Time(dateobs)).to(u.meter).value) header.set( 'rsun_obs', sun.solar_semidiameter_angular_size( Time(dateobs)).value) header.set( 'hglt_obs', sun.heliographic_solar_center(Time(dateobs))[1].value) else: header.set( 'dsun_obs', sun.earth_distance(Time(dateobs)).to(u.meter).value) header.set('rsun_obs', sun.angular_radius(Time(dateobs)).value) header.set('hglt_obs', sun.L0(Time(dateobs)).value) except: # this works for astropy.io.fits if tdur_s: header.append(('exptime', tdur_s)) else: header.append(('exptime', 1.)) header.append(('p_angle', hel['p0'])) header.append(('hgln_obs', 0.)) header.append(('rsun_ref', sun.constants.radius.value)) if sunpyver <= 1: header.append( ('dsun_obs', sun.sunearth_distance(Time(dateobs)).to( u.meter).value)) header.append(('rsun_obs', sun.solar_semidiameter_angular_size( Time(dateobs)).value)) header.append(('hglt_obs', sun.heliographic_solar_center( Time(dateobs))[1].value)) else: header.append( ('dsun_obs', sun.earth_distance(Time(dateobs)).to(u.meter).value)) header.append( ('rsun_obs', sun.angular_radius(Time(dateobs)).value)) header.append(('hglt_obs', sun.L0(Time(dateobs)).value)) # check if stokes parameter exist exist_stokes = False stokes_mapper = { 'I': 1, 'Q': 2, 'U': 3, 'V': 4, 'RR': -1, 'LL': -2, 'RL': -3, 'LR': -4, 'XX': -5, 'YY': -6, 'XY': -7, 'YX': -8 } if 'CRVAL3' in header.keys(): if header['CTYPE3'] == 'STOKES': stokenum = header['CRVAL3'] exist_stokes = True if 'CRVAL4' in header.keys(): if header['CTYPE4'] == 'STOKES': stokenum = header['CRVAL4'] exist_stokes = True if exist_stokes: if stokenum in stokes_mapper.values(): stokesstr = list(stokes_mapper.keys())[list( stokes_mapper.values()).index(stokenum)] else: print('Stokes parameter {0:d} not recognized'.format( stokenum)) if verbose: print('This image is in Stokes ' + stokesstr) else: print( 'STOKES Information does not seem to exist! Assuming Stokes I' ) stokenum = 1 # intensity units to brightness temperature if toTb: # get restoring beam info bmaj = bmajs[n] bmin = bmins[n] beamunit = beamunits[n] data = hdu[ 0].data # remember the data order is reversed due to the FITS convension keys = list(header.keys()) values = list(header.values()) # which axis is frequency? faxis = keys[values.index('FREQ')][-1] faxis_ind = ndim - int(faxis) # find out the polarization of this image k_b = qa.constants('k')['value'] c_l = qa.constants('c')['value'] # Always use 2*kb for all polarizations const = 2. * k_b / c_l**2 if header['BUNIT'].lower() == 'jy/beam': header['BUNIT'] = 'K' header['BTYPE'] = 'Brightness Temperature' for i in range(dshape[faxis_ind]): nu = header['CRVAL' + faxis] + header['CDELT' + faxis] * ( i + 1 - header['CRPIX' + faxis]) if header['CUNIT' + faxis] == 'KHz': nu *= 1e3 if header['CUNIT' + faxis] == 'MHz': nu *= 1e6 if header['CUNIT' + faxis] == 'GHz': nu *= 1e9 if len(bmaj) > 1: # multiple (per-plane) beams bmajtmp = bmaj[i] bmintmp = bmin[i] else: # one single beam bmajtmp = bmaj[0] bmintmp = bmin[0] if beamunit == 'arcsec': bmaj0 = np.radians(bmajtmp / 3600.) bmin0 = np.radians(bmintmp / 3600.) if beamunit == 'arcmin': bmaj0 = np.radians(bmajtmp / 60.) bmin0 = np.radians(bmintmp / 60.) if beamunit == 'deg': bmaj0 = np.radians(bmajtmp) bmin0 = np.radians(bmintmp) if beamunit == 'rad': bmaj0 = bmajtmp bmin0 = bmintmp beam_area = bmaj0 * bmin0 * np.pi / (4. * log(2.)) factor = const * nu**2 # SI unit jy_to_si = 1e-26 # print(nu/1e9, beam_area, factor) factor2 = sclfactor # if sclfactor: # factor2 = 100. if faxis == '3': data[:, i, :, :] *= jy_to_si / beam_area / factor * factor2 if faxis == '4': data[ i, :, :, :] *= jy_to_si / beam_area / factor * factor2 header = fu.headerfix(header) hdu.flush() hdu.close() if ndim - np.count_nonzero(np.array(dshape) == 1) > 3: docompress = False ''' Caveat: only 1D, 2D, or 3D images are currently supported by the astropy fits compression. If a n-dimensional image data array does not have at least n-3 single-dimensional entries, force docompress to be False ''' print( 'warning: The fits data contains more than 3 non squeezable dimensions. Skipping fits compression..' ) if docompress: fitsftmp = fitsf + ".tmp.fits" os.system("mv {} {}".format(fitsf, fitsftmp)) hdu = pyfits.open(fitsftmp) hdu[0].verify('fix') header = hdu[0].header data = hdu[0].data fu.write_compressed_image_fits(fitsf, data, header, compression_type='RICE_1', quantize_level=4.0) os.system("rm -rf {}".format(fitsftmp)) if deletehistory: ms_restorehistory(vis) return fitsfile
def plt_qlook_image(imres, figdir=None, verbose=True, synoptic=False): from matplotlib import pyplot as plt from sunpy import map as smap from sunpy import sun from matplotlib import colors import astropy.units as u if not figdir: figdir = './' nspw = len(set(imres['Spw'])) plttimes = list(set(imres['BeginTime'])) ntime = len(plttimes) # sort the imres according to time images = np.array(imres['ImageName']) btimes = Time(imres['BeginTime']) etimes = Time(imres['EndTime']) spws = np.array(imres['Spw']) suc = np.array(imres['Succeeded']) inds = btimes.argsort() images_sort = images[inds].reshape(ntime, nspw) btimes_sort = btimes[inds].reshape(ntime, nspw) suc_sort = suc[inds].reshape(ntime, nspw) spws_sort = spws[inds].reshape(ntime, nspw) if verbose: print '{0:d} figures to plot'.format(ntime) plt.ioff() fig = plt.figure(figsize=(8, 8)) plt.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0) for i in range(ntime): plt.ioff() plt.clf() plttime = btimes_sort[i, 0] tofd = plttime.mjd - np.fix(plttime.mjd) suci = suc_sort[i] if not synoptic: if tofd < 16. / 24. or sum( suci ) < nspw - 2: # if time of the day is before 16 UT (and 24 UT), skip plotting (because the old antennas are not tracking) continue #fig=plt.figure(figsize=(9,6)) #fig.suptitle('EOVSA @ '+plttime.iso[:19]) if synoptic: fig.text(0.01, 0.98, plttime.iso[:10], color='w', fontweight='bold', fontsize=12, ha='left') else: fig.text(0.01, 0.98, plttime.iso[:19], color='w', fontweight='bold', fontsize=12, ha='left') if verbose: print 'Plotting image at: ', plttime.iso for n in range(nspw): plt.ioff() image = images_sort[i, n] #fig.add_subplot(nspw/3, 3, n+1) fig.add_subplot(nspw / 2, 2, n + 1) if suci[n]: try: eomap = smap.Map(image) except: continue sz = eomap.data.shape if len(sz) == 4: eomap.data = eomap.data.reshape((sz[2], sz[3])) eomap.data[np.isnan(eomap.data)] = 0.0 #resample the image for plotting dim = u.Quantity([256, 256], u.pixel) eomap = eomap.resample(dim) eomap.plot_settings['cmap'] = plt.get_cmap('jet') eomap.plot_settings['norm'] = colors.Normalize(vmin=-1e5, vmax=1e6) eomap.plot() if not synoptic: eomap.draw_limb() eomap.draw_grid() ax = plt.gca() ax.set_xlim([-1080, 1080]) ax.set_ylim([-1080, 1080]) spwran = spws_sort[i, n] freqran = [int(s) * 0.5 + 2.9 for s in spwran.split('~')] ax.text(0.98, 0.01, '{0:.1f} - {1:.1f} GHz'.format(freqran[0], freqran[1]), color='w', transform=ax.transAxes, fontweight='bold', ha='right') ax.set_title(' ') #ax.set_title('spw '+spws_sort[i,n]) #ax.text(0.01,0.02, plttime.isot,transform=ax.transAxes,color='white') ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels(['']) ax.set_yticklabels(['']) else: #make an empty map data = np.zeros((512, 512)) header = { "DATE-OBS": plttime.isot, "EXPTIME": 0., "CDELT1": 5., "NAXIS1": 512, "CRVAL1": 0., "CRPIX1": 257, "CUNIT1": "arcsec", "CTYPE1": "HPLN-TAN", "CDELT2": 5., "NAXIS2": 512, "CRVAL2": 0., "CRPIX2": 257, "CUNIT2": "arcsec", "CTYPE2": "HPLT-TAN", "HGLT_OBS": sun.heliographic_solar_center(plttime)[1].value, "HGLN_OBS": 0., "RSUN_OBS": sun.solar_semidiameter_angular_size(plttime).value, "RSUN_REF": sun.constants.radius.value, "DSUN_OBS": sun.sunearth_distance(plttime).to(u.meter).value, } eomap = smap.Map(data, header) eomap.plot_settings['cmap'] = plt.get_cmap('jet') eomap.plot_settings['norm'] = colors.Normalize(vmin=-1e5, vmax=1e6) eomap.plot() if not synoptic: eomap.draw_limb() eomap.draw_grid() ax = plt.gca() ax.set_xlim([-1080, 1080]) ax.set_ylim([-1080, 1080]) #ax.set_title('spw '+spwran+'( )')) spwran = spws_sort[i, n] freqran = [int(s) * 0.5 + 2.9 for s in spwran.split('~')] spwran = spws_sort[i, n] #ax.set_title('{0:.1f} - {1:.1f} GHz'.format(freqran[0],freqran[1])) ax.text(0.98, 0.01, '{0:.1f} - {1:.1f} GHz'.format(freqran[0], freqran[1]), color='w', transform=ax.transAxes, fontweight='bold', ha='right') ax.set_title(' ') #ax.text(0.01,0.02, plttime.isot,transform=ax.transAxes,color='white') ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels(['']) ax.set_yticklabels(['']) fig_tdt = plttime.to_datetime() if synoptic: fig_subdir = fig_tdt.strftime("%Y/") figname = 'eovsa_qlimg_' + plttime.iso[:10].replace('-', '') + '.png' else: fig_subdir = fig_tdt.strftime("%Y/%m/%d/") figname = 'eovsa_qlimg_' + plttime.isot.replace(':', '').replace( '-', '')[:15] + '.png' figdir_ = figdir + fig_subdir if not os.path.exists(figdir_): os.makedirs(figdir_) if verbose: print 'Saving plot to :' + figdir_ + figname plt.savefig(figdir_ + figname) plt.close(fig)
def imreg(vis=None, ephem=None, msinfo=None, reftime=None, imagefile=None, fitsfile=None, beamfile=None, \ offsetfile=None, toTb=None, scl100=None, verbose=False, p_ang = False, overwrite = True, usephacenter=False): ia = iatool() if not imagefile: raise ValueError, 'Please specify input image' if not reftime: raise ValueError, 'Please specify reference time corresponding to the input image' if not fitsfile: fitsfile = [img + '.fits' for img in imagefile] if len(imagefile) != len(reftime): raise ValueError, 'Number of input images does not equal to number of helio coord headers!' if len(imagefile) != len(fitsfile): raise ValueError, 'Number of input images does not equal to number of output fits files!' nimg = len(imagefile) if verbose: print str(nimg) + ' images to process...' helio = ephem_to_helio(vis, ephem=ephem, msinfo=msinfo, reftime=reftime, usephacenter=usephacenter) for n, img in enumerate(imagefile): if verbose: print 'processing image #' + str(n) fitsf = fitsfile[n] hel = helio[n] if not os.path.exists(img): raise ValueError, 'Please specify input image' if os.path.exists(fitsf) and not overwrite: raise ValueError, 'Specified fits file already exists and overwrite is set to False. Aborting...' else: p0 = hel['p0'] ia.open(img) imr = ia.rotate(pa=str(-p0) + 'deg') imr.tofits(fitsf, history=False, overwrite=overwrite) imr.close() sum = ia.summary() ia.close() # construct the standard fits header # RA and DEC of the reference pixel crpix1 and crpix2 (imra, imdec) = (sum['refval'][0], sum['refval'][1]) # find out the difference of the image center to the CASA phase center # RA and DEC difference in arcseconds ddec = degrees((imdec - hel['dec_fld'])) * 3600. dra = degrees((imra - hel['ra_fld']) * cos(hel['dec_fld'])) * 3600. # Convert into image heliocentric offsets prad = -radians(hel['p0']) dx = (-dra) * cos(prad) - ddec * sin(prad) dy = (-dra) * sin(prad) + ddec * cos(prad) if offsetfile: try: offset = np.load(offsetfile) except: raise ValueError, 'The specified offsetfile does not exist!' reftimes_d = offset['reftimes_d'] xoffs = offset['xoffs'] yoffs = offset['yoffs'] timg_d = hel['reftime'] ind = bisect.bisect_left(reftimes_d, timg_d) xoff = xoffs[ind - 1] yoff = yoffs[ind - 1] else: xoff = hel['refx'] yoff = hel['refy'] if verbose: print 'offset of image phase center to visibility phase center (arcsec): ', dx, dy print 'offset of visibility phase center to solar disk center (arcsec): ', xoff, yoff (crval1, crval2) = (xoff + dx, yoff + dy) # update the fits header to heliocentric coordinates hdu = pyfits.open(fitsf, mode='update') header = hdu[0].header (cdelt1, cdelt2) = (-header['cdelt1'] * 3600., header['cdelt2'] * 3600. ) # Original CDELT1, 2 are for RA and DEC in degrees header['cdelt1'] = cdelt1 header['cdelt2'] = cdelt2 header['cunit1'] = 'arcsec' header['cunit2'] = 'arcsec' header['crval1'] = crval1 header['crval2'] = crval2 header['ctype1'] = 'HPLN-TAN' header['ctype2'] = 'HPLT-TAN' header['date-obs'] = hel['date-obs'] #begin time of the image if not p_ang: hel['p0'] = 0 try: # this works for pyfits version of CASA 4.7.0 but not CASA 4.6.0 header.update('exptime', hel['exptime']) header.update('p_angle', hel['p0']) header.update( 'dsun_obs', sun.sunearth_distance(Time(hel['date-obs'])).to(u.meter).value) header.update( 'rsun_obs', sun.solar_semidiameter_angular_size(Time( hel['date-obs'])).value) header.update('rsun_ref', sun.constants.radius.value) header.update('hgln_obs', 0.) header.update( 'hglt_obs', sun.heliographic_solar_center(Time(hel['date-obs']))[1].value) except: # this works for astropy.io.fits header.append(('exptime', hel['exptime'])) header.append(('p_angle', hel['p0'])) header.append( ('dsun_obs', sun.sunearth_distance(Time(hel['date-obs'])).to( u.meter).value)) header.append(('rsun_obs', sun.solar_semidiameter_angular_size( Time(hel['date-obs'])).value)) header.append(('rsun_ref', sun.constants.radius.value)) header.append(('hgln_obs', 0.)) header.append(('hglt_obs', sun.heliographic_solar_center(Time( hel['date-obs']))[1].value)) # header.update('comment', 'Fits header updated to heliocentric coordinates by Bin Chen') # update intensity units, i.e. to brightness temperature? if toTb: # get restoring beam info (bmajs, bmins, bpas, beamunits, bpaunits) = getbeam(imagefile=imagefile, beamfile=beamfile) bmaj = bmajs[n] bmin = bmins[n] beamunit = beamunits[n] data = hdu[ 0].data # remember the data order is reversed due to the FITS convension dim = data.ndim sz = data.shape keys = header.keys() values = header.values() # which axis is frequency? faxis = keys[values.index('FREQ')][-1] faxis_ind = dim - int(faxis) if header['BUNIT'].lower() == 'jy/beam': header['BUNIT'] = 'K' for i in range(sz[faxis_ind]): nu = header['CRVAL' + faxis] + header['CDELT' + faxis] * \ (i + 1 - header['CRPIX' + faxis]) if header['CUNIT' + faxis] == 'KHz': nu *= 1e3 if header['CUNIT' + faxis] == 'MHz': nu *= 1e6 if header['CUNIT' + faxis] == 'GHz': nu *= 1e9 if len(bmaj) > 1: # multiple (per-plane) beams bmajtmp = bmaj[i] bmintmp = bmin[i] else: # one single beam bmajtmp = bmaj[0] bmintmp = bmin[0] if beamunit == 'arcsec': bmaj0 = np.radians(bmajtmp / 3600.) bmin0 = np.radians(bmajtmp / 3600.) if beamunit == 'arcmin': bmaj0 = np.radians(bmajtmp / 60.) bmin0 = np.radians(bmintmp / 60.) if beamunit == 'deg': bmaj0 = np.radians(bmajtmp) bmin0 = np.radians(bmintmp) if beamunit == 'rad': bmaj0 = bmajtmp bmin0 = bmintmp beam_area = bmaj0 * bmin0 * np.pi / (4. * log(2.)) k_b = qa.constants('k')['value'] c_l = qa.constants('c')['value'] factor = 2. * k_b * nu**2 / c_l**2 # SI unit jy_to_si = 1e-26 # print nu/1e9, beam_area, factor factor2 = 1. if scl100: factor2 = 100. if faxis == '3': data[:, i, :, :] *= jy_to_si / beam_area / factor * factor2 if faxis == '4': data[ i, :, :, :] *= jy_to_si / beam_area / factor * factor2 hdu.flush() hdu.close()
def imreg(vis=None, ephem=None, msinfo=None, imagefile=None, timerange=None, reftime=None, fitsfile=None, beamfile=None, offsetfile=None, toTb=None, scl100=None, verbose=False, p_ang=False, overwrite=True, usephacenter=True, deletehistory=False): ''' main routine to register CASA images Required Inputs: vis: STRING. CASA measurement set from which the image is derived imagefile: STRING or LIST. name of the input CASA image timerange: STRING or LIST. timerange used to generate the CASA image, must have the same length as the input images. Each element should be in CASA standard time format, e.g., '2012/03/03/12:00:00~2012/03/03/13:00:00' Optional Inputs: msinfo: DICTIONARY. CASA MS information, output from read_msinfo. If not provided, generate one from the supplied vis ephem: DICTIONARY. solar ephem, output from read_horizons. If not provided, query JPL Horizons based on time info of the vis (internet connection required) fitsfile: STRING or LIST. name of the output registered fits files reftime: STRING or LIST. Each element should be in CASA standard time format, e.g., '2012/03/03/12:00:00' offsetfile: optionally provide an offset with a series of solar x and y offsets with timestamps toTb: Bool. Convert the default Jy/beam to brightness temperature? scl100: Bool. If True, scale the image values up by 100 (to compensate VLA 20 dB attenuator) verbose: Bool. Show more diagnostic info if True. usephacenter: Bool -- if True, correct for the RA and DEC in the ms file based on solar empheris. Otherwise assume the phasecenter is correctly pointed to the solar disk center (EOVSA case) ''' ia = iatool() if deletehistory: msclearhistory(vis) if verbose: import time t0 = time.time() prtidx = 1 print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 if not imagefile: raise ValueError, 'Please specify input image' if not timerange: raise ValueError, 'Please specify timerange of the input image' if type(imagefile) == str: imagefile = [imagefile] if type(timerange) == str: timerange = [timerange] if not fitsfile: fitsfile = [img + '.fits' for img in imagefile] if type(fitsfile) == str: fitsfile = [fitsfile] nimg = len(imagefile) if len(timerange) != nimg: raise ValueError, 'Number of input images does not equal to number of timeranges!' if len(fitsfile) != nimg: raise ValueError, 'Number of input images does not equal to number of output fits files!' nimg = len(imagefile) if verbose: print str(nimg) + ' images to process...' if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 if reftime: # use as reference time to find solar disk RA and DEC to register the image, but not the actual timerange associated with the image if type(reftime) == str: reftime = [reftime] * nimg if len(reftime) != nimg: raise ValueError, 'Number of reference times does not match that of input images!' helio = ephem_to_helio(vis, ephem=ephem, msinfo=msinfo, reftime=reftime, usephacenter=usephacenter) else: # use the supplied timerange to register the image helio = ephem_to_helio(vis, ephem=ephem, msinfo=msinfo, reftime=timerange, usephacenter=usephacenter) if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 for n, img in enumerate(imagefile): if verbose: print 'processing image #' + str(n) fitsf = fitsfile[n] timeran = timerange[n] # obtain duration of the image as FITS header exptime try: [tbg0, tend0] = timeran.split('~') tbg_d = qa.getvalue(qa.convert(qa.totime(tbg0), 'd'))[0] tend_d = qa.getvalue(qa.convert(qa.totime(tend0), 'd'))[0] tdur_s = (tend_d - tbg_d) * 3600. * 24. dateobs = qa.time(qa.quantity(tbg_d, 'd'), form='fits', prec=10)[0] except: print 'Error in converting the input timerange: ' + str( timeran) + '. Proceeding to the next image...' continue if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 hel = helio[n] if not os.path.exists(img): raise ValueError, 'Please specify input image' if os.path.exists(fitsf) and not overwrite: raise ValueError, 'Specified fits file already exists and overwrite is set to False. Aborting...' else: p0 = hel['p0'] ia.open(img) imr = ia.rotate(pa=str(-p0) + 'deg') imr.tofits(fitsf, history=False, overwrite=overwrite) imr.close() imsum = ia.summary() ia.close() if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 # construct the standard fits header # RA and DEC of the reference pixel crpix1 and crpix2 (imra, imdec) = (imsum['refval'][0], imsum['refval'][1]) # find out the difference of the image center to the CASA phase center # RA and DEC difference in arcseconds ddec = degrees((imdec - hel['dec_fld'])) * 3600. dra = degrees((imra - hel['ra_fld']) * cos(hel['dec_fld'])) * 3600. # Convert into image heliocentric offsets prad = -radians(hel['p0']) dx = (-dra) * cos(prad) - ddec * sin(prad) dy = (-dra) * sin(prad) + ddec * cos(prad) if offsetfile: try: offset = np.load(offsetfile) except: raise ValueError, 'The specified offsetfile does not exist!' reftimes_d = offset['reftimes_d'] xoffs = offset['xoffs'] yoffs = offset['yoffs'] timg_d = hel['reftime'] ind = bisect.bisect_left(reftimes_d, timg_d) xoff = xoffs[ind - 1] yoff = yoffs[ind - 1] else: xoff = hel['refx'] yoff = hel['refy'] if verbose: print 'offset of image phase center to visibility phase center (arcsec): ', dx, dy print 'offset of visibility phase center to solar disk center (arcsec): ', xoff, yoff (crval1, crval2) = (xoff + dx, yoff + dy) # update the fits header to heliocentric coordinates if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 hdu = pyfits.open(fitsf, mode='update') if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 header = hdu[0].header (cdelt1, cdelt2) = (-header['cdelt1'] * 3600., header['cdelt2'] * 3600. ) # Original CDELT1, 2 are for RA and DEC in degrees header['cdelt1'] = cdelt1 header['cdelt2'] = cdelt2 header['cunit1'] = 'arcsec' header['cunit2'] = 'arcsec' header['crval1'] = crval1 header['crval2'] = crval2 header['ctype1'] = 'HPLN-TAN' header['ctype2'] = 'HPLT-TAN' header['date-obs'] = dateobs # begin time of the image if not p_ang: hel['p0'] = 0 try: # this works for pyfits version of CASA 4.7.0 but not CASA 4.6.0 if tdur_s: header.set('exptime', tdur_s) else: header.set('exptime', 1.) header.set('p_angle', hel['p0']) header.set('dsun_obs', sun.sunearth_distance(Time(dateobs)).to(u.meter).value) header.set( 'rsun_obs', sun.solar_semidiameter_angular_size(Time(dateobs)).value) header.set('rsun_ref', sun.constants.radius.value) header.set('hgln_obs', 0.) header.set('hglt_obs', sun.heliographic_solar_center(Time(dateobs))[1].value) except: # this works for astropy.io.fits if tdur_s: header.append(('exptime', tdur_s)) else: header.append(('exptime', 1.)) header.append(('p_angle', hel['p0'])) header.append( ('dsun_obs', sun.sunearth_distance(Time(dateobs)).to(u.meter).value)) header.append( ('rsun_obs', sun.solar_semidiameter_angular_size(Time(dateobs)).value)) header.append(('rsun_ref', sun.constants.radius.value)) header.append(('hgln_obs', 0.)) header.append( ('hglt_obs', sun.heliographic_solar_center(Time(dateobs))[1].value)) if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 # update intensity units, i.e. to brightness temperature? if toTb: # get restoring beam info (bmajs, bmins, bpas, beamunits, bpaunits) = getbeam(imagefile=imagefile, beamfile=beamfile) bmaj = bmajs[n] bmin = bmins[n] beamunit = beamunits[n] data = hdu[ 0].data # remember the data order is reversed due to the FITS convension dim = data.ndim sz = data.shape keys = header.keys() values = header.values() # which axis is frequency? faxis = keys[values.index('FREQ')][-1] faxis_ind = dim - int(faxis) if header['BUNIT'].lower() == 'jy/beam': header['BUNIT'] = 'K' header['BTYPE'] = 'Brightness Temperature' for i in range(sz[faxis_ind]): nu = header['CRVAL' + faxis] + header['CDELT' + faxis] * ( i + 1 - header['CRPIX' + faxis]) if header['CUNIT' + faxis] == 'KHz': nu *= 1e3 if header['CUNIT' + faxis] == 'MHz': nu *= 1e6 if header['CUNIT' + faxis] == 'GHz': nu *= 1e9 if len(bmaj) > 1: # multiple (per-plane) beams bmajtmp = bmaj[i] bmintmp = bmin[i] else: # one single beam bmajtmp = bmaj[0] bmintmp = bmin[0] if beamunit == 'arcsec': bmaj0 = np.radians(bmajtmp / 3600.) bmin0 = np.radians(bmajtmp / 3600.) if beamunit == 'arcmin': bmaj0 = np.radians(bmajtmp / 60.) bmin0 = np.radians(bmintmp / 60.) if beamunit == 'deg': bmaj0 = np.radians(bmajtmp) bmin0 = np.radians(bmintmp) if beamunit == 'rad': bmaj0 = bmajtmp bmin0 = bmintmp beam_area = bmaj0 * bmin0 * np.pi / (4. * log(2.)) k_b = qa.constants('k')['value'] c_l = qa.constants('c')['value'] factor = 2. * k_b * nu**2 / c_l**2 # SI unit jy_to_si = 1e-26 # print nu/1e9, beam_area, factor factor2 = 1. if scl100: factor2 = 100. if faxis == '3': data[:, i, :, :] *= jy_to_si / beam_area / factor * factor2 if faxis == '4': data[ i, :, :, :] *= jy_to_si / beam_area / factor * factor2 if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1 hdu.flush() hdu.close() if verbose: print('point {}: {}'.format(prtidx, time.time() - t0)) prtidx += 1
def plt_qlook_image(imres, figdir=None, specdata=None, verbose=True, stokes='I,V', fov=None): from matplotlib import pyplot as plt from sunpy import map as smap from sunpy import sun import astropy.units as u if not figdir: figdir = './' observatory = 'EOVSA' polmap = {'RR': 0, 'LL': 1, 'I': 0, 'V': 1} pols = stokes.split(',') npols = len(pols) # SRL = set(['RR', 'LL']) # SXY = set(['XX', 'YY', 'XY', 'YX']) Spw = sorted(list(set(imres['Spw']))) nspw = len(Spw) # Freq = set(imres['Freq']) ## list is an unhashable type Freq = sorted(uniq(imres['Freq'])) plttimes = list(set(imres['BeginTime'])) ntime = len(plttimes) # sort the imres according to time images = np.array(imres['ImageName']) btimes = Time(imres['BeginTime']) etimes = Time(imres['EndTime']) spws = np.array(imres['Spw']) suc = np.array(imres['Succeeded']) inds = btimes.argsort() images_sort = images[inds].reshape(ntime, nspw) btimes_sort = btimes[inds].reshape(ntime, nspw) suc_sort = suc[inds].reshape(ntime, nspw) spws_sort = spws[inds].reshape(ntime, nspw) if verbose: print '{0:d} figures to plot'.format(ntime) plt.ioff() import matplotlib.gridspec as gridspec spec = specdata['spec'] (npol, nbl, nfreq, ntim) = spec.shape tidx = range(ntim) fidx = range(nfreq) tim = specdata['tim'] freq = specdata['freq'] freqghz = freq / 1e9 pol = ''.join(pols) spec_tim = Time(specdata['tim'] / 3600. / 24., format='mjd') timstrr = spec_tim.plot_date if npols == 1: if pol == 'RR': spec_plt = spec[0, 0, :, :] elif pol == 'LL': spec_plt = spec[1, 0, :, :] elif pol == 'I': spec_plt = (spec[0, 0, :, :] + spec[1, 0, :, :]) / 2. elif pol == 'V': spec_plt = (spec[0, 0, :, :] - spec[1, 0, :, :]) / 2. spec_plt = [spec_plt] print 'plot the dynamic spectrum in pol ' + pol # ax1 = fig.add_subplot(211) hnspw = nspw / 2 ncols = hnspw nrows = 2 + 2 # 1 image: 1x1, 1 dspec:2x4 fig = plt.figure(figsize=(8, 8)) gs = gridspec.GridSpec(nrows, ncols) axs = [plt.subplot(gs[0, 0])] for ll in range(1, nspw): axs.append(plt.subplot(gs[ll / hnspw, ll % hnspw], sharex=axs[0], sharey=axs[0])) for ll in range(nspw): axs.append(plt.subplot(gs[ll / hnspw + 2, ll % hnspw], sharex=axs[0], sharey=axs[0])) axs_dspec = [plt.subplot(gs[2:, :])] cmaps = ['jet'] elif npols == 2: R_plot = np.absolute(spec[0, 0, :, :]) L_plot = np.absolute(spec[1, 0, :, :]) if pol == 'RRLL': spec_plt = [R_plot, L_plot] polstr = ['RR', 'LL'] cmaps = ['jet'] * 2 if pol == 'IV': I_plot = (R_plot + L_plot) / 2. V_plot = (R_plot - L_plot) / 2. spec_plt = [I_plot, V_plot] polstr = ['I', 'V'] cmaps = ['jet', 'RdBu'] print 'plot the dynamic spectrum in pol ' + pol hnspw = nspw / 2 ncols = hnspw + 2 # 1 image: 1x1, 1 dspec:2x2 nrows = 2 + 2 fig = plt.figure(figsize=(12, 8)) gs = gridspec.GridSpec(nrows, ncols) axs = [plt.subplot(gs[0, 0])] for ll in range(1, nspw): axs.append(plt.subplot(gs[ll / hnspw, ll % hnspw], sharex=axs[0], sharey=axs[0])) for ll in range(nspw): axs.append(plt.subplot(gs[ll / hnspw + 2, ll % hnspw], sharex=axs[0], sharey=axs[0])) axs_dspec = [plt.subplot(gs[:2, hnspw:])] axs_dspec.append(plt.subplot(gs[2:, hnspw:], sharex=axs_dspec[0], sharey=axs_dspec[0])) fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0) timetext = fig.text(0.01, 0.98, '', color='w', fontweight='bold', fontsize=12, ha='left', va='top') for i in range(ntime): plt.ioff() # plt.clf() for ax in axs: ax.cla() plttime = btimes_sort[i, 0] # tofd = plttime.mjd - np.fix(plttime.mjd) suci = suc_sort[i] # if tofd < 16. / 24. or sum( # suci) < nspw - 2: # if time of the day is before 16 UT (and 24 UT), skip plotting (because the old antennas are not tracking) # continue # fig=plt.figure(figsize=(9,6)) # fig.suptitle('EOVSA @ '+plttime.iso[:19]) timetext.set_text(plttime.iso[:19]) if verbose: print 'Plotting image at: ', plttime.iso if i == 0: dspecvspans = [] for pol in range(npols): ax = axs_dspec[pol] ax.pcolormesh(timstrr, freqghz, spec_plt[pol], cmap=cmaps[pol]) ax.xaxis_date() ax.xaxis.set_major_formatter(DateFormatter("%H:%M:%S")) # plt.xticks(rotation=45) ax.set_xlim(timstrr[tidx[0]], timstrr[tidx[-1]]) ax.set_ylim(freqghz[fidx[0]], freqghz[fidx[-1]]) ax.set_xlabel('Time [UT]') ax.set_ylabel('Frequency [GHz]') for idx, freq in enumerate(Freq): ax.axhspan(freq[0], freq[1], linestyle='dotted', edgecolor='w', alpha=0.7, facecolor='none') xtext, ytext = ax.transAxes.inverted().transform(ax.transData.transform([timstrr[tidx[0]], np.mean(freq)])) ax.text(xtext + 0.01, ytext, 'spw ' + Spw[idx], color='w', transform=ax.transAxes, fontweight='bold', ha='left', va='center', fontsize=8, alpha=0.5) ax.text(0.01, 0.98, 'Stokes ' + pols[pol], color='w', transform=ax.transAxes, fontweight='bold', ha='left', va='top') dspecvspans.append(ax.axvspan(btimes[i].plot_date, etimes[i].plot_date, color='w', alpha=0.4)) ax_pos = ax.get_position().extents x0, y0, x1, y1 = ax_pos h, v = x1 - x0, y1 - y0 x0_new = x0 + 0.15 * h y0_new = y0 + 0.15 * v x1_new = x1 - 0.05 * h y1_new = y1 - 0.05 * v ax.set_position(mpl.transforms.Bbox([[x0_new, y0_new], [x1_new, y1_new]])) else: for pol in range(npols): xy = dspecvspans[pol].get_xy() xy[:, 0][np.array([0, 1, 4])] = btimes[i].plot_date xy[:, 0][np.array([2, 3])] = etimes[i].plot_date dspecvspans[pol].set_xy(xy) for n in range(nspw): image = images_sort[i, n] # fig.add_subplot(nspw/3, 3, n+1) # fig.add_subplot(2, nspw / 2, n + 1) for pol in range(npols): if suci[n]: try: eomap = smap.Map(image) except: continue sz = eomap.data.shape if len(sz) == 4: eomap.data = eomap.data[min(polmap[pols[pol]], eomap.meta['naxis4'] - 1), 0, :, :].reshape((sz[2], sz[3])) # resample the image for plotting if fov is not None: fov = [np.array(ll) for ll in fov] pad = max(np.diff(fov[0])[0], np.diff(fov[1])[0]) eomap = eomap.submap((fov[0] + np.array([-1.0, 1.0]) * pad) * u.arcsec, (fov[1] + np.array([-1.0, 1.0]) * pad) * u.arcsec) else: dim = u.Quantity([256, 256], u.pixel) eomap = eomap.resample(dim) eomap.plot_settings['cmap'] = plt.get_cmap(cmaps[pol]) # import pdb # pdb.set_trace() eomap.plot(axes=axs[n + nspw * pol]) eomap.draw_limb() eomap.draw_grid() ax = plt.gca() ax.set_autoscale_on(False) if fov: # pass ax.set_xlim(fov[0]) ax.set_ylim(fov[1]) else: ax.set_xlim([-1080, 1080]) ax.set_ylim([-1080, 1080]) spwran = spws_sort[i, n] # freqran = [int(s) * 0.5 + 2.9 for s in spwran.split('~')] # if len(freqran) == 1: # ax.text(0.98, 0.01, '{0:.1f} GHz'.format(freqran[0]), color='w', # transform=ax.transAxes, fontweight='bold', ha='right') # else: # ax.text(0.98, 0.01, '{0:.1f} - {1:.1f} GHz'.format(freqran[0], freqran[1]), color='w', # transform=ax.transAxes, fontweight='bold', ha='right') ax.text(0.98, 0.01, 'Stokes {1} @ {0:.3f} GHz'.format(eomap.meta['crval3'] / 1e9, pols[pol]), color='w', transform=ax.transAxes, fontweight='bold', ha='right') ax.set_title(' ') # ax.set_title('spw '+spws_sort[i,n]) # ax.text(0.01,0.02, plttime.isot,transform=ax.transAxes,color='white') ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) else: # make an empty map data = np.zeros((512, 512)) header = {"DATE-OBS": plttime.isot, "EXPTIME": 0., "CDELT1": 5., "NAXIS1": 512, "CRVAL1": 0., "CRPIX1": 257, "CUNIT1": "arcsec", "CTYPE1": "HPLN-TAN", "CDELT2": 5., "NAXIS2": 512, "CRVAL2": 0., "CRPIX2": 257, "CUNIT2": "arcsec", "CTYPE2": "HPLT-TAN", "HGLT_OBS": sun.heliographic_solar_center(plttime)[1].value, "HGLN_OBS": 0., "RSUN_OBS": sun.solar_semidiameter_angular_size(plttime).value, "RSUN_REF": sun.constants.radius.value, "DSUN_OBS": sun.sunearth_distance(plttime).to(u.meter).value, } eomap = smap.Map(data, header) # resample the image for plotting if fov: fov = [np.array(ll) for ll in fov] pad = max(np.diff(fov[0])[0], np.diff(fov[1])[0]) try: eomap = eomap.submap((fov[0] + np.array([-1.0, 1.0]) * pad) * u.arcsec, (fov[1] + np.array([-1.0, 1.0]) * pad) * u.arcsec) except: x0, x1 = fov[0] + np.array([-1.0, 1.0]) * pad y0, y1 = fov[1] + np.array([-1.0, 1.0]) * pad bl = SkyCoord(x0 * u.arcsec, y0 * u.arcsec, frame=eomap.coordinate_frame) tr = SkyCoord(x1 * u.arcsec, y1 * u.arcsec, frame=eomap.coordinate_frame) eomap = eomap.submap(bl, tr) else: dim = u.Quantity([256, 256], u.pixel) eomap = eomap.resample(dim) eomap.plot_settings['cmap'] = plt.get_cmap(cmaps[pol]) eomap.plot(axes=axs[n + nspw * pol]) eomap.draw_limb() eomap.draw_grid() ax = plt.gca() ax.set_autoscale_on(False) if fov: # pass ax.set_xlim(fov[0]) ax.set_ylim(fov[1]) else: ax.set_xlim([-1080, 1080]) ax.set_ylim([-1080, 1080]) # ax.set_title('spw '+spwran+'( )')) spwran = spws_sort[i, n] freqran = [int(s) * 0.5 + 2.9 for s in spwran.split('~')] spwran = spws_sort[i, n] # ax.set_title('{0:.1f} - {1:.1f} GHz'.format(freqran[0],freqran[1])) # ax.text(0.98, 0.01, '{0:.1f} - {1:.1f} GHz'.format(freqran[0], freqran[1]), color='w', # transform=ax.transAxes, fontweight='bold', ha='right') ax.text(0.98, 0.01, 'Stokes {1} @ {0:.3f} GHz'.format(0., pols[pol]), color='w', transform=ax.transAxes, fontweight='bold', ha='right') ax.set_title(' ') # ax.text(0.01,0.02, plttime.isot,transform=ax.transAxes,color='white') ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) figname = observatory + '_qlimg_' + plttime.isot.replace(':', '').replace('-', '')[:19] + '.png' fig_tdt = plttime.to_datetime() # fig_subdir = fig_tdt.strftime("%Y/%m/%d/") figdir_ = figdir # + fig_subdir if not os.path.exists(figdir_): os.makedirs(figdir_) if verbose: print 'Saving plot to: ' + os.path.join(figdir_, figname) plt.savefig(os.path.join(figdir_, figname)) plt.close(fig) DButil.img2html_movie(figdir_)
def plt_qlook_image(imres, figdir=None, verbose=True): from matplotlib import pyplot as plt from sunpy import map as smap from sunpy import sun import astropy.units as u if not figdir: figdir = './' nspw = len(set(imres['Spw'])) plttimes = list(set(imres['BeginTime'])) ntime = len(plttimes) # sort the imres according to time images = np.array(imres['ImageName']) btimes = Time(imres['BeginTime']) etimes = Time(imres['EndTime']) spws = np.array(imres['Spw']) suc = np.array(imres['Succeeded']) inds = btimes.argsort() images_sort = images[inds].reshape(ntime, nspw) btimes_sort = btimes[inds].reshape(ntime, nspw) suc_sort = suc[inds].reshape(ntime, nspw) spws_sort = spws[inds].reshape(ntime, nspw) if verbose: print '{0:d} figures to plot'.format(ntime) for i in range(ntime): #for i in range(1): plt.ioff() fig = plt.figure(figsize=(11, 6)) plttime = btimes_sort[i, 0] fig.suptitle('EOVSA @ ' + plttime.iso[:19]) if verbose: print 'Plotting image at: ', plttime.iso suci = suc_sort[i] for n in range(nspw): plt.ioff() image = images_sort[i, n] fig.add_subplot(nspw / 3, 3, n + 1) if suci[n]: try: eomap = smap.Map(image) except: continue sz = eomap.data.shape if len(sz) == 4: eomap.data = eomap.data.reshape((sz[2], sz[3])) eomap.plot_settings['cmap'] = plt.get_cmap('jet') eomap.plot() eomap.draw_limb() eomap.draw_grid() ax = plt.gca() ax.set_xlim([-1050, 1050]) ax.set_ylim([-1050, 1050]) ax.set_title('spw ' + spws_sort[i, n]) #ax.text(0.01,0.02, plttime.isot,transform=ax.transAxes,color='white') if n != nspw - 3: ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels(['']) ax.set_yticklabels(['']) else: #make an empty map data = np.zeros((512, 512)) header = { "DATE-OBS": plttime.isot, "EXPTIME": 0., "CDELT1": 5., "NAXIS1": 512, "CRVAL1": 0., "CRPIX1": 257, "CUNIT1": "arcsec", "CTYPE1": "HPLN-TAN", "CDELT2": 5., "NAXIS2": 512, "CRVAL2": 0., "CRPIX2": 257, "CUNIT2": "arcsec", "CTYPE2": "HPLT-TAN", "HGLT_OBS": sun.heliographic_solar_center(plttime)[1].value, "HGLN_OBS": 0., "RSUN_OBS": sun.solar_semidiameter_angular_size(plttime).value, "RSUN_REF": sun.constants.radius.value, "DSUN_OBS": sun.sunearth_distance(plttime).to(u.meter).value, } eomap = smap.Map(data, header) eomap.plot_settings['cmap'] = plt.get_cmap('jet') eomap.plot() eomap.draw_limb() eomap.draw_grid() ax = plt.gca() ax.set_xlim([-1050, 1050]) ax.set_ylim([-1050, 1050]) ax.set_title('spw ' + spws_sort[i, n]) #ax.text(0.01,0.02, plttime.isot,transform=ax.transAxes,color='white') if n != 6: ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels(['']) ax.set_yticklabels(['']) figname = 'eovsa_qlimg_' + plttime.isot.replace(':', '').replace( '-', '')[:15] + '.png' fig_tdt = plttime.to_datetime() fig_subdir = fig_tdt.strftime("%Y/%m/%d/") figdir_ = figdir + fig_subdir if not os.path.exists(figdir_): os.makedirs(figdir_) if verbose: print 'Saving plot to :' + figdir_ + figname plt.savefig(figdir_ + figname) plt.close(fig)