Skip to content

Commit

Permalink
improve visualization tools for OS
Browse files Browse the repository at this point in the history
  • Loading branch information
pgris committed Aug 6, 2020
1 parent 3f9db11 commit 20eec8d
Showing 1 changed file with 206 additions and 27 deletions.
233 changes: 206 additions & 27 deletions sn_tools/sn_visu.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
from descartes.patch import PolygonPatch
from shapely.geometry import MultiPolygon
from shapely.ops import unary_union
from sn_tools.sn_obs import LSSTPointing, renameFields
import time
import itertools
import numpy.lib.recfunctions as rf
import pandas as pd

from shapely import geometry
from shapely import affinity

def fieldType(obs, RACol, DecCol):
"""
Expand Down Expand Up @@ -47,6 +47,72 @@ def fieldType(obs, RACol, DecCol):

return df.to_records(index=False)

def LSSTPointing(xc, yc, angle_rot=0., area=None, maxbound=None):
"""
Function to build a focal plane for LSST
Parameters
---------------
xc: float
x-position of the center FP (RA)
yc: float
y-position of the center FP (Dec)
angle_rot: float, opt
angle of rotation of the FP (default: 0.)
area: float
area for the FP (default: None)
maxbound: float
to reduce area (default: None)
Returns
----------
LSST FP (geometry.Polygon)
"""

"""
arr = [[3, 0], [12, 0], [12, 1], [13, 1], [13, 2], [14, 2], [14, 3], [15, 3],
[15, 12], [14, 12], [14, 13], [13, 13], [
13, 14], [12, 14], [12, 15],
[3, 15], [3, 14], [2, 14], [2, 13], [1, 13], [1, 12], [0, 12],
[0, 3], [1, 3], [1, 2], [2, 2], [2, 1], [3, 1]]
"""
# this is a quarter of LSST FP (with corner rafts)
arr = [[0.0, 7.5], [4.5, 7.5], [4.5, 6.5], [5.5, 6.5], [
5.5, 5.5], [6.5, 5.5], [6.5, 4.5], [7.5, 4.5], [7.5, 0.0]]

# this is a quarter of LSST FP (without corner rafts)
arr = [[0.0, 7.5], [4.5, 7.5], [4.5, 4.5], [7.5, 4.5], [7.5, 0.0]]
if maxbound is not None:
arr = [[0.0, maxbound], [maxbound*4.5/7.5, maxbound], [maxbound*4.5 /
7.5, maxbound*4.5/7.5], [maxbound, maxbound*4.5/7.5], [maxbound, 0.0]]
# symmetry I: y -> -y
arrcp = list(arr)
for val in arr[::-1]:
if val[1] > 0.:
arrcp.append([val[0], -val[1]])

# symmetry II: x -> -x
arr = list(arrcp)
for val in arrcp[::-1]:
if val[0] > 0.:
arr.append([-val[0], val[1]])

# build polygon
poly_orig = geometry.Polygon(arr)

# set area
if area is not None:
poly_orig = affinity.scale(poly_orig, xfact=np.sqrt(
area/poly_orig.area), yfact=np.sqrt(area/poly_orig.area))

# set rotation angle
rotated_poly = affinity.rotate(poly_orig, angle_rot)

return affinity.translate(rotated_poly,
xoff=xc-rotated_poly.centroid.x,
yoff=yc-rotated_poly.centroid.y)


def area(polylist):
"""Estimate area of a set of polygons (without overlaps)
Expand Down Expand Up @@ -76,10 +142,8 @@ class to get a snapshot of the (RA, Dec) pointings (LSST FP) observed map per ni
location dir of the db file
dbName: str
name of the db of interest. Extension: npy!
night_min: int, opt
min night to consider (default: 1)
night_max: int, opt
max night to consider (default: 3)
nights: list(int)
list of nights to display
saveFig: bool, opt
to save the figure result or not (default: False)
areaTime: bool, opt
Expand All @@ -89,7 +153,7 @@ class to get a snapshot of the (RA, Dec) pointings (LSST FP) observed map per ni
"""

def __init__(self, dbDir, dbName, nightmin=1, nightmax=3, saveFig=False, areaTime=False, realTime=False):
def __init__(self, dbDir, dbName, nights=[1,2,3], saveFig=False, areaTime=False, realTime=False):

self.dbName = dbName
self.saveFig = saveFig
Expand All @@ -102,11 +166,16 @@ def __init__(self, dbDir, dbName, nightmin=1, nightmax=3, saveFig=False, areaTim
obs.sort(order='observationStartMJD')

# Select observations
"""
idx = obs['night'] <= nightmax
idx &= obs['night'] >= nightmin
obs = obs[idx]

for night in range(np.min(obs['night']), np.max(obs['night'])+1):
"""
idx = np.isin(obs['night'],nights)
obs = obs[idx]

#for night in range(np.min(obs['night']), np.max(obs['night'])+1):
for night in nights:
# if night > np.min(obs['night']):
# self.ax.clear()
idx = obs['night'] == night
Expand All @@ -120,14 +189,29 @@ def __init__(self, dbDir, dbName, nightmin=1, nightmax=3, saveFig=False, areaTim
mjds = obs_disp['observationStartMJD']-mjd0
nchanges = len(list(itertools.groupby(obs_disp['filter'])))-1
iwfd = obs_disp['fieldType'] == 'WFD'
selWFD = obs_disp[iwfd]
nchanges_noddf = len(
list(itertools.groupby(obs_disp[iwfd]['filter'])))-1
list(itertools.groupby(selWFD['filter'])))-1

countfilter = {}
for b in 'ugrizy':
idx = selWFD['filter'] == b
countfilter[b] = len(selWFD[idx])
iddf = obs_disp['fieldType'] != 'WFD'
nddf = len(obs_disp[iddf])

nvisits = ''
for key, vals in countfilter.items():
nvisits += '{} : {} - '.format(key,int(vals))

nvisits += 'ddf : {}'.format(nddf)

self.fig.suptitle(
'night {} - filter changes: {}/{}'.format(night, nchanges_noddf, nchanges))
'night {} \n filter changes: {}/{} \n {}'.format(night, nchanges_noddf, nchanges,nvisits))

# area observed versus time
for val in obs_disp:
pointing = LSSTPointing(val['fieldRA'], val['fieldDec'])
pointing = LSSTPointing(val['fieldRA'], val['fieldDec'],area=1.)
if val['fieldType'] == 'WFD':
p = PolygonPatch(
pointing, facecolor=self.colors[val['filter']], edgecolor=self.colors[val['filter']])
Expand Down Expand Up @@ -245,7 +329,7 @@ class CadenceMovie:
draw observed area vs time in an embedded histo (default: False)
"""

def __init__(self, dbDir, dbName, nights=1, title='', total=600, sub=100, fps=24, saveMovie=False, realTime=False, saveFig=False, areaTime=False):
def __init__(self, dbDir, dbName, nights=[1,2,3], title='', total=600, sub=100, fps=24, saveMovie=False, realTime=False, saveFig=False, areaTime=False):

self.realTime = realTime
self.plotParams()
Expand All @@ -271,26 +355,41 @@ def __init__(self, dbDir, dbName, nights=1, title='', total=600, sub=100, fps=24
self.customize()

# Select observations
"""
idx = obs['night'] <= nights
obs = obs[idx]
"""

idx = np.isin(obs['night'],nights)
obs = obs[idx]

#print('hello',np.unique(obs['night']))

self.polylist = []
if saveMovie:
# Warning : to save the movie ffmpeg needs to be installed!
print(manimation.writers.list())
FFMpegWriter = manimation.writers['ffmpeg']
writer_type = 'pillow'
extension = 'gif'
"""
writer_type = 'ffmpeg'
extension = 'mp4'
"""
#FFMpegWriter = manimation.writers['ffmpeg']
Writer = manimation.writers[writer_type]
metadata = dict(title=title, artist='Matplotlib',
comment=title)
writer = FFMpegWriter(
fps=fps, metadata=metadata, bitrate=6000)
writer = anim.FFMpegWriter(fps=30, codec='hevc')
Name_mp4 = title
#writer = FFMpegWriter(fps=fps, metadata=metadata, bitrate=6000)
writer = Writer(fps=fps, metadata=metadata, bitrate=6000)
#writer = anim.FFMpegWriter(fps=30, codec='hevc')
Name_mp4 = '{}.{}'.format(title,extension)
print('name for saving',Name_mp4)
with writer.saving(self.fig, Name_mp4, 250):
self.loopObs(obs, writer=writer)
else:
self.loopObs(obs)

def showObs(self, obs, nchanges, nchanges_noddf, area, mjd0):
def showObs(self, obs, nchanges, nchanges_noddf, area, mjd0,countfilter,nddf):
""" Display observation (RA, Dec) as time (MJD) evolves.
Parameters
Expand All @@ -309,12 +408,19 @@ def showObs(self, obs, nchanges, nchanges_noddf, area, mjd0):
# grab MJD and night
mjd = obs['observationStartMJD']
night = obs['night']
moonPhase = obs['moonPhase']

nvisits = ''
for key, vals in countfilter.items():
nvisits += '{} : {} - '.format(key,int(vals))

nvisits += 'ddf : {}'.format(nddf)

self.fig.suptitle(
'night {} - MJD {} \n filter changes: {}/{}'.format(night, np.round(mjd, 3), nchanges_noddf, nchanges))
'night {} - MJD {} \n filter changes: {}/{} \n {}'.format(night, np.round(mjd, 3), nchanges_noddf, nchanges,nvisits))

# LSST focal plane corresponding to this pointing
pointing = LSSTPointing(obs['fieldRA'], obs['fieldDec'])
pointing = LSSTPointing(obs['fieldRA'], obs['fieldDec'],area=1.)
if obs['fieldType'] == 'WFD':
p = PolygonPatch(
pointing, facecolor=self.colors[obs['filter']], edgecolor=self.colors[obs['filter']])
Expand All @@ -339,7 +445,8 @@ def loopObs(self, obs, writer=None):
default: None
"""

for night in range(np.min(obs['night']), np.max(obs['night'])+1):
#for night in range(np.min(obs['night']), np.max(obs['night'])+1):
for night in np.unique(obs['night']):
idx = obs['night'] == night
obs_disp = obs[idx]
# get fieldtype(WFD or DDF)
Expand All @@ -351,17 +458,26 @@ def loopObs(self, obs, writer=None):
sel = obs_disp[:k]
nchanges = len(list(itertools.groupby(sel['filter'])))-1
ifw = sel['fieldType'] == 'WFD'
selWFD = sel[ifw]
nchanges_noddf = len(
list(itertools.groupby(sel[ifw]['filter'])))-1
list(itertools.groupby(selWFD['filter'])))-1
countfilter = {}
for b in 'ugrizy':
idx = selWFD['filter'] == b
countfilter[b] = len(selWFD[idx])
iddf = sel['fieldType'] != 'WFD'
nddf = len(sel[iddf])

# show observations
if self.areaTime:
self.polylist.append(LSSTPointing(
obs_disp[k]['fieldRA'], obs_disp[k]['fieldDec']))
obs_disp[k]['fieldRA'], obs_disp[k]['fieldDec']),area=1.)
self.showObs(obs_disp[k], nchanges, nchanges_noddf,
area(self.polylist), mjd0)
area(self.polylist), mjd0,countfilter,nddf)
else:
#print(sel[['observationStartMJD','fieldRA','fieldDec','filter']])
self.showObs(obs_disp[k], nchanges, nchanges_noddf,
0., mjd0)
0., mjd0,countfilter,nddf)
self.fig.canvas.flush_events()
if writer:
writer.grab_frame()
Expand Down Expand Up @@ -407,7 +523,7 @@ def customize(self):
self.ax.set_xlabel('RA [deg]')
self.ax.set_ylabel('Dec [deg]')
self.ax.set_xlim(0, 360.)
self.ax.set_ylim(-90., 10.)
self.ax.set_ylim(-90., 20.)

colorfilters = []
for band in self.colors.keys():
Expand All @@ -417,3 +533,66 @@ def customize(self):
color='k', label='ddf'))
plt.legend(handles=colorfilters, loc='upper left',
bbox_to_anchor=(1., 0.5))

def renameFields(tab):
"""
Function to rename fields
Parameters
--------------
tab: array
original array of data
Returns
---------
array of data with modified field names
"""
corresp = {}

fillCorresp(tab, corresp, 'mjd', 'observationStartMJD')
fillCorresp(tab, corresp, 'RA', 'fieldRA')
fillCorresp(tab, corresp, 'Ra', 'fieldRA')
fillCorresp(tab, corresp, 'Dec', 'fieldDec')
fillCorresp(tab, corresp, 'band', 'filter')
fillCorresp(tab, corresp, 'exptime', 'visitExposureTime')
fillCorresp(tab, corresp, 'nexp', 'numExposures')

# print(tab.dtype)

rb = np.copy(tab)
for vv, vals in corresp.items():
rb = rf.drop_fields(rb, vv)
if vv != 'band':
rb = rf.append_fields(rb, vals, tab[vv])
else:
rb = rf.append_fields(rb, vals, tab[vv], dtypes='<U9')
# rb = rf.rename_fields(rb, {vv: vals})

# return rf.rename_fields(tab, corresp)
return rb

def fillCorresp(tab, corres, vara, varb):
"""
Function to fill a dict used to change colnams of a nupy array
Parameters
--------------
tab: array
original array of data
corresp: dict
keys: string, items: string
vara: str
colname in tab to change
varb: str
new colname to replace vara
Returns
---------
dict with str as keys and items
correspondence vara<-> varb
"""

if vara in tab.dtype.names and varb not in tab.dtype.names:
corres[vara] = varb

0 comments on commit 20eec8d

Please sign in to comment.