AstroToolkit 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,215 @@
1
+ import pandas as pd
2
+ from astropy.table import Table
3
+ from astropy.io import fits
4
+ from astropy.visualization import PercentileInterval, AsinhStretch
5
+ from io import BytesIO
6
+ import PIL
7
+ from PIL import Image
8
+ import requests
9
+ import numpy as np
10
+ from astropy.wcs import WCS
11
+ import warnings
12
+ from astropy.utils.exceptions import AstropyWarning
13
+ import math
14
+ import astropy
15
+ import re
16
+ from bokeh.plotting import figure
17
+ from bokeh.models import Range1d
18
+
19
+ #Ignore warning about deprecated header
20
+ warnings.simplefilter('ignore', category=AstropyWarning)
21
+
22
+ def get_image(ra,dec,size=30,band='g'):
23
+ service='https://api.skymapper.nci.org.au/public/siap/dr2/query'
24
+ url=f'{service}?POS={ra},{dec}&SIZE={size},{size}&BAND={band}&FORMAT=image/fits&VERB=3&INTERSECT=covers&RESPONSEFORMAT=CSV'
25
+
26
+ try:
27
+ table=pd.read_csv(url)
28
+ table=Table.from_pandas(table)
29
+ except:
30
+ print('[SkyMapper: get_image_data] Error: experiencing issues with SkyMapper.')
31
+ return None, None, None
32
+
33
+ if len(table)>0:
34
+ urlMain=table['get_image'][0]
35
+ else:
36
+ print('[SkyMapper: get_image_data] Error: no SkyMapper images found using given fields.')
37
+ return None, None, None
38
+
39
+ # Need to add filter check functionality
40
+ '''
41
+ shortnames=[]
42
+ for i in range(0,len(table)):
43
+ shortnames.append(table['shortname'][i])
44
+
45
+ missing_filters=[]
46
+ if len(table)!=len(band):
47
+ for i in range(0,len(band)):
48
+ filterCheck='.'+band[i]+'.'
49
+ if any(filterCheck in shortname for shortname in shortnames):
50
+ pass
51
+ else:
52
+ print('[PanSTARRS: get_image_data] Note: no PanSTARRS data in '+band[i]+' band')
53
+ missing_filters.append(band[i])
54
+
55
+ for i in range(0,len(missing_filters)):
56
+ band=band.replace(missing_filters[i],'')
57
+ '''
58
+
59
+ try:
60
+ r=requests.get(urlMain,timeout=15)
61
+ if r.status_code!=200:
62
+ print('[SkyMapper: get_image_data] Error: experiencing issues with SkyMapper.')
63
+ return None, None, None
64
+ except:
65
+ print('[SkyMapper: get_image_data] Error: experiencing issues with SkyMapper.')
66
+ return None, None, None
67
+
68
+ try:
69
+ fh=fits.open(BytesIO(r.content))
70
+ fitsImage=fh[0].data
71
+ image_header=fh[0].header
72
+ fitsImage[np.isnan(fitsImage)]=0.0
73
+ transform=AsinhStretch()+PercentileInterval(95)
74
+ image=transform(fitsImage)
75
+
76
+ if not isinstance(image,np.ndarray):
77
+ print('[SkyMapper: get_image_data] Error: no SkyMapper images found using given fields.')
78
+ return None, None, None
79
+
80
+ return image, image_header, band
81
+
82
+ except:
83
+ print('[SkyMapper: get_image_data] Error: no SkyMapper images found using given fields.')
84
+ return None, None, None
85
+
86
+ def get_info(ra,dec,size=30,band='g'):
87
+ ra,dec,size,sizeAS,band=input_management(ra=ra,dec=dec,size=size,band=band)
88
+
89
+ image_data=get_image(ra=ra,dec=dec,size=size,band=band)[1]
90
+
91
+ if not isinstance(image_data,astropy.io.fits.header.Header):
92
+ return None, None
93
+
94
+ wcs=WCS(image_data)
95
+
96
+ mjd=image_data['MJD-OBS']
97
+
98
+ return wcs, mjd
99
+
100
+ def input_management(ra,dec,size=30,band='g'):
101
+ if len(band)!=len(set(band)):
102
+ raise Exception('duplicate detected in filter selection')
103
+
104
+ if not isinstance(ra,float):
105
+ try:
106
+ ra=float(ra)
107
+ except:
108
+ raise Exception('object RA must be a float or an integer')
109
+ if not isinstance(dec,float):
110
+ try:
111
+ dec=float(dec)
112
+ except:
113
+ raise Exception('object DEC must be a float or an integer')
114
+
115
+ band=band.lower()
116
+
117
+ if isinstance(size,int):
118
+ pass
119
+ else:
120
+ raise Exception('size must take an integer value')
121
+
122
+ if size>600:
123
+ raise Exception('SkyMapper image takes a maximum size of 10 arcmin')
124
+
125
+ sizeAS=size
126
+ size=size/3600
127
+
128
+ if re.match('^[grizuv]+$', band):
129
+ pass
130
+ else:
131
+ raise Exception('bands must be in list: [g,r,i,z,u,v]')
132
+
133
+ band=list(band)
134
+ temp_string=''
135
+ for i in range(0,len(band)):
136
+ temp_string+=(band[i]+',')
137
+ band=temp_string[:-1]
138
+
139
+ return ra,dec,size,sizeAS,band
140
+
141
+ def get_plot(ra,dec,size=30,band='g'):
142
+ ra,dec,size,sizeAS,band=input_management(ra,dec,size=size,band=band)
143
+
144
+ # Create axes and plot image
145
+ plot=figure(width=400,height=400,title=f'SkyMapper Image ({sizeAS}")')
146
+ # Fixes scaling issue
147
+ plot.min_border=75
148
+
149
+ plot.xgrid.grid_line_color=None
150
+ plot.ygrid.grid_line_color=None
151
+
152
+ image,image_data,_=get_image(ra=ra,dec=dec,size=size,band=band)
153
+
154
+ if not isinstance(image,np.ndarray) or not isinstance(image_data,astropy.io.fits.header.Header):
155
+ return None
156
+
157
+ # Get x and y limit (in pixels) from image header
158
+ xlim=image_data['NAXIS1']
159
+ ylim=image_data['NAXIS2']
160
+
161
+ # Get points on axes in world coordinates (deg)
162
+ points=[]
163
+ wcs=WCS(image_data)
164
+
165
+ # Get array of pixels in x and y
166
+ x_points=np.arange(start=0,stop=xlim+1,step=1)
167
+ y_points=np.arange(start=0,stop=ylim+1,step=1)
168
+
169
+ # Apply transformation to coordinates
170
+ coords=wcs.all_pix2world(x_points,y_points,1)
171
+ x_points,y_points=coords[0],coords[1]
172
+
173
+ # Get image size in degrees
174
+ x_range=max(x_points)-min(x_points)
175
+ y_range=max(y_points)-min(y_points)
176
+
177
+ plot.x_range=Range1d(max(x_points),min(x_points))
178
+ plot.y_range=Range1d(min(y_points),max(y_points))
179
+
180
+ plot.image(image=[image],x=x_points[0],y=y_points[0],dw=x_range,dh=y_range,palette='Greys256',level="image",origin='bottom_right',anchor='bottom_right')
181
+
182
+ return plot
183
+
184
+ def SkyMapperQueryCoords(ObjRa,ObjDec,radius=3):
185
+ radius=radius/3600
186
+
187
+ #Had to use JSON format to get this to work, the CSV format used is not easily formattable by pandas
188
+ url=f'https://skymapper.anu.edu.au/sm-cone/public/query?RA={ObjRa}&DEC={ObjDec}&SR={radius}&RESPONSEFORMAT=CSV'
189
+ try:
190
+ r=requests.get(url)
191
+ except:
192
+ print('[SkyMapper: SkyMapperQueryCoords] Error: experiencing issues with SkyMapper.')
193
+ return None
194
+
195
+ if r.status_code!=200:
196
+ print('[SkyMapper: SkyMapperQueryCoords] Error: experiencing issues with SkyMapper.')
197
+ return None
198
+
199
+ data=BytesIO(r.content)
200
+ try:
201
+ data=pd.read_csv(data)
202
+ except:
203
+ print('[SkyMapper: SkyMapperQueryCoords] Note: No data found using given coordinates')
204
+
205
+ return data
206
+
207
+ def SkyMapperGetPhotometryCoords(ObjRa,ObjDec,radius=3):
208
+ data=SkyMapperQueryCoords(ObjRa,ObjDec,radius=radius)
209
+
210
+ if not isinstance(data,pd.DataFrame) or data.empty:
211
+ print('[SkyMapper: SkyMapperGetPhotometryCoords] Note: No SkyMapper data at given coordinates.')
212
+ return None
213
+
214
+ photometry=data[['raj2000','dej2000','object_id','g_psf','e_g_psf','r_psf','e_r_psf','i_psf','e_i_psf','z_psf','e_z_psf','u_psf','e_u_psf','v_psf','e_v_psf']].copy()
215
+ return photometry
@@ -0,0 +1,45 @@
1
+ from astroquery.vizier import Vizier
2
+ import astropy.coordinates as coord
3
+ import pandas as pd
4
+ from astropy import units as u
5
+
6
+ catalogue_name='II/246/out'
7
+
8
+ Vizier.ROW_LIMIT = -1
9
+
10
+ def get_data(ra,dec,radius=3):
11
+ data=[]
12
+
13
+ if not isinstance(radius,int) and not isinstance(radius,float):
14
+ raise Exception('search radius must be a float or an integer')
15
+
16
+ if not isinstance(ra,float):
17
+ try:
18
+ ra=float(ra)
19
+ except:
20
+ raise Exception('object RA must be a float or an integer')
21
+ if not isinstance(dec,float):
22
+ try:
23
+ dec=float(dec)
24
+ except:
25
+ raise Exception('object DEC must be a float or an integer')
26
+
27
+ v=Vizier(columns=['**'])
28
+
29
+ #Sends Vizier query, can return multiple objects in given search radius
30
+ data.append(v.query_region(coord.SkyCoord(ra=ra,dec=dec,unit=(u.deg,u.deg),frame='icrs'),width=radius*u.arcsec,catalog=catalogue_name))
31
+ if len(data[0])==0:
32
+ print('[TWOMASS: get_data] Error: no 2MASS data found at given coordinates')
33
+ return None
34
+ data=data[0][0].to_pandas()
35
+ data=data.reset_index(drop=True)
36
+ return data
37
+
38
+ def get_photometry(ra,dec,radius=3):
39
+ TWOMASSdata=get_data(ra,dec,radius=radius)
40
+ if not isinstance(TWOMASSdata,pd.DataFrame) or TWOMASSdata.empty:
41
+ return None
42
+
43
+ photometry=TWOMASSdata[['RAJ2000','DEJ2000','_2MASS','Jmag','e_Jmag','Hmag','e_Hmag','Kmag','e_Kmag']].copy()
44
+
45
+ return photometry
@@ -0,0 +1,45 @@
1
+ from astroquery.vizier import Vizier
2
+ import astropy.coordinates as coord
3
+ import pandas as pd
4
+ from astropy import units as u
5
+
6
+ catalogue_name='II/311/wise'
7
+
8
+ Vizier.ROW_LIMIT = -1
9
+
10
+ def get_data(ra,dec,radius=3):
11
+ data=[]
12
+
13
+ if not isinstance(radius,int) and not isinstance(radius,float):
14
+ raise Exception('search radius must be a float or an integer')
15
+
16
+ if not isinstance(ra,float):
17
+ try:
18
+ ra=float(ra)
19
+ except:
20
+ raise Exception('object RA must be a float or an integer')
21
+ if not isinstance(dec,float):
22
+ try:
23
+ dec=float(dec)
24
+ except:
25
+ raise Exception('object DEC must be a float or an integer')
26
+
27
+ v=Vizier(columns=['**'])
28
+
29
+ #Sends Vizier query, can return multiple objects in given search radius
30
+ data.append(v.query_region(coord.SkyCoord(ra=ra,dec=dec,unit=(u.deg,u.deg),frame='icrs'),width=radius*u.arcsec,catalog=catalogue_name))
31
+ if len(data[0])==0:
32
+ print('[WISE: get_data] Error: no WISE data found at given coordinates')
33
+ return None
34
+ data=data[0][0].to_pandas()
35
+ data=data.reset_index(drop=True)
36
+ return data
37
+
38
+ def get_photometry(ra,dec,radius=3):
39
+ WISEdata=get_data(ra,dec,radius=radius)
40
+ if not isinstance(WISEdata,pd.DataFrame) or WISEdata.empty:
41
+ return None
42
+
43
+ photometry=WISEdata[['RAJ2000','DEJ2000','WISE','W1mag','e_W1mag','W2mag','e_W2mag','W3mag','e_W3mag','W4mag','e_W4mag']].copy()
44
+
45
+ return photometry
@@ -0,0 +1,206 @@
1
+ import requests
2
+ import pandas as pd
3
+ from io import BytesIO
4
+ import re
5
+ import numpy as np
6
+ from requests.adapters import HTTPAdapter, Retry
7
+ import matplotlib
8
+ from bokeh.plotting import figure, show
9
+ from bokeh.models import Whisker, ColumnDataSource
10
+ from bokeh.transform import linear_cmap
11
+ from bokeh.layouts import gridplot
12
+
13
+ def getData(ra,dec,radius=3):
14
+ #Filters inputs
15
+ if not isinstance(ra,float):
16
+ try:
17
+ ra=float(ra)
18
+ except:
19
+ raise Exception('object RA must be a float or an integer')
20
+ if not isinstance(radius,float):
21
+ try:
22
+ radius=float(radius)
23
+ except:
24
+ raise Exception('search radius must be a float or an integer')
25
+ if not isinstance(dec,float):
26
+ try:
27
+ dec=float(dec)
28
+ except:
29
+ raise Exception('object DEC must be a float or an integer')
30
+
31
+ #Convert radius into degrees
32
+ radius=radius/3600
33
+
34
+ #Perform query
35
+ service='https://irsa.ipac.caltech.edu/cgi-bin/ZTF/nph_light_curves'
36
+ url=f'{service}?POS=CIRCLE {ra} {dec} {radius}&BANDNAME=g,r,i&FORMAT=CSV'
37
+
38
+ s=requests.Session()
39
+ retries=Retry(total=5,backoff_factor=0.1,status_forcelist=[500,502,503,504])
40
+ s.mount('http://',HTTPAdapter(max_retries=retries))
41
+ try:
42
+ r=s.get(url,timeout=15)
43
+ except:
44
+ print('[ZTF: getData] Error: experiencing issues with ZTF.')
45
+ return [None, None, None]
46
+
47
+ if r.status_code!=200:
48
+ print('[ZTF: getData] Error: experiencing issues with ZTF.')
49
+ return [None, None, None]
50
+
51
+ #Convert to pandas array (containing all bands)
52
+ data=pd.read_csv(BytesIO(r.content))
53
+ if len(data)==0:
54
+ print('[ZTF: getData] Error: no ZTF data found using given fields')
55
+ return [None, None, None]
56
+
57
+ #Split into separate bands
58
+ gData=data.loc[data['filtercode']=='zg']
59
+ rData=data.loc[data['filtercode']=='zr']
60
+ iData=data.loc[data['filtercode']=='zi']
61
+
62
+ gData,rData,iData=gData.reset_index(drop=True),rData.reset_index(drop=True),iData.reset_index(drop=True)
63
+
64
+ if gData.empty:
65
+ gData=None
66
+ if rData.empty:
67
+ rData=None
68
+ if iData.empty:
69
+ iData=None
70
+
71
+ Data=[gData,rData,iData]
72
+
73
+ return Data
74
+
75
+ def getLightCurve(ra,dec,radius=3,return_raw=False):
76
+ Data=getData(ra=ra,dec=dec,radius=radius)
77
+
78
+ try:
79
+ if Data==None:
80
+ if return_raw==False:
81
+ return None
82
+ else:
83
+ return None, None, None
84
+ except:
85
+ pass
86
+
87
+ #Check if there is any returned data
88
+ if not isinstance(Data[0],pd.DataFrame) and not isinstance(Data[1],pd.DataFrame) and not isinstance(Data[2],pd.DataFrame):
89
+ if return_raw==False:
90
+ return None
91
+ else:
92
+ return None, None, None
93
+
94
+ gBand,rBand,iBand=False,False,False
95
+
96
+ g_colourmap=matplotlib.colors.LinearSegmentedColormap.from_list('',['greenyellow','forestgreen','greenyellow'])
97
+ g_palette=[matplotlib.colors.rgb2hex(c) for c in g_colourmap(np.linspace(0,1,255))]
98
+
99
+ r_colourmap=matplotlib.colors.LinearSegmentedColormap.from_list('',['yellow','red','yellow'])
100
+ r_palette=[matplotlib.colors.rgb2hex(c) for c in r_colourmap(np.linspace(0,1,255))]
101
+
102
+ i_colourmap=matplotlib.colors.LinearSegmentedColormap.from_list('',['aqua','royalblue','aqua'])
103
+ i_palette=[matplotlib.colors.rgb2hex(c) for c in i_colourmap(np.linspace(0,1,255))]
104
+
105
+ #Separate data into different bands, find number of subplots needed and which bands have data
106
+ if isinstance(Data[0],pd.DataFrame):
107
+ gData=Data[0]
108
+ g_hjd=gData.loc[:,'hjd'].tolist()
109
+ g_hjd_min=min(g_hjd)
110
+ g_hjd=[x-g_hjd_min for x in g_hjd]
111
+ g_mag=gData.loc[:,'mag'].tolist()
112
+ g_mag=np.array(g_mag)
113
+ g_mag_err=gData.loc[:,'magerr'].tolist()
114
+ gBand=True
115
+ if isinstance(Data[1],pd.DataFrame):
116
+ rData=Data[1]
117
+ r_hjd=rData.loc[:,'hjd'].tolist()
118
+ r_hjd_min=min(r_hjd)
119
+ r_hjd=[x-r_hjd_min for x in r_hjd]
120
+ r_mag=rData.loc[:,'mag'].tolist()
121
+ r_mag=np.array(r_mag)
122
+ r_mag_err=rData.loc[:,'magerr'].tolist()
123
+ rBand=True
124
+ if isinstance(Data[2],pd.DataFrame):
125
+ iData=Data[2]
126
+ i_hjd=iData.loc[:,'hjd'].tolist()
127
+ i_hjd_min=min(i_hjd)
128
+ i_hjd=[x-i_hjd_min for x in i_hjd]
129
+ i_mag=iData.loc[:,'mag'].tolist()
130
+ i_mag=np.array(i_mag)
131
+ i_mag_err=iData.loc[:,'magerr'].tolist()
132
+ iBand=True
133
+
134
+ #Plot data
135
+ if gBand:
136
+ gPlot=figure(width=400,height=400,title='ZTF g Lightcurve',x_axis_label=r'\[\text{Observation Date [days]}\]',y_axis_label=r'\[\text{g}\]')
137
+
138
+ gPlot.y_range.flipped=True
139
+
140
+ upper=[x+e for x,e in zip(g_mag,g_mag_err)]
141
+ lower=[x-e for x,e in zip(g_mag,g_mag_err)]
142
+ source=ColumnDataSource(data=dict(hjd=g_hjd,mag=g_mag,upper=upper,lower=lower))
143
+
144
+ g_mapper=linear_cmap(field_name='mag',palette=g_palette,low=min(g_mag),high=max(g_mag))
145
+
146
+ gPlot.circle(x='hjd',y='mag',source=source,color=g_mapper)
147
+ errors=Whisker(source=source,base='hjd',upper='upper',lower='lower',line_width=0.5,line_color='forestgreen')
148
+ errors.upper_head.line_width,errors.lower_head.line_width=0.5,0.5
149
+ errors.upper_head.size,errors.lower_head.size=3,3
150
+ errors.upper_head.line_color,errors.lower_head.line_color='forestgreen','forestgreen'
151
+
152
+ gPlot.add_layout(errors)
153
+ else:
154
+ gPlot=None
155
+
156
+ if rBand:
157
+ rPlot=figure(width=400,height=400,title='ZTF r Lightcurve',x_axis_label=r'\[\text{Observation Date [days]}\]',y_axis_label=r'\[\text{r}\]')
158
+
159
+ rPlot.y_range.flipped=True
160
+
161
+ upper=[x+e for x,e in zip(r_mag,r_mag_err)]
162
+ lower=[x-e for x,e in zip(r_mag,r_mag_err)]
163
+ source=ColumnDataSource(data=dict(hjd=r_hjd,mag=r_mag,upper=upper,lower=lower))
164
+
165
+ r_mapper=linear_cmap(field_name='mag',palette=r_palette,low=min(r_mag),high=max(r_mag))
166
+
167
+ rPlot.circle(x='hjd',y='mag',source=source,color=r_mapper)
168
+ errors=Whisker(source=source,base='hjd',upper='upper',lower='lower',line_width=0.5,line_color='red')
169
+ errors.upper_head.line_width,errors.lower_head.line_width=0.5,0.5
170
+ errors.upper_head.size,errors.lower_head.size=3,3
171
+ errors.upper_head.line_color,errors.lower_head.line_color='red','red'
172
+
173
+ rPlot.add_layout(errors)
174
+ else:
175
+ rPlot=None
176
+
177
+ if iBand:
178
+ iPlot=figure(width=400,height=400,title='ZTF i Lightcurve',x_axis_label=r'\[\text{Observation Date [days]}\]',y_axis_label=r'\[\text{i}\]')
179
+
180
+ iPlot.y_range.flipped=True
181
+
182
+ upper=[x+e for x,e in zip(i_mag,i_mag_err)]
183
+ lower=[x-e for x,e in zip(i_mag,i_mag_err)]
184
+ source=ColumnDataSource(data=dict(hjd=i_hjd,mag=i_mag,upper=upper,lower=lower))
185
+
186
+ i_mapper=linear_cmap(field_name='mag',palette=i_palette,low=min(i_mag),high=max(i_mag))
187
+
188
+ iPlot.circle(x='hjd',y='mag',source=source,color=i_mapper)
189
+ errors=Whisker(source=source,base='hjd',upper='upper',lower='lower',line_width=0.5,line_color='royalblue')
190
+ errors.upper_head.line_width,errors.lower_head.line_width=0.5,0.5
191
+ errors.upper_head.size,errors.lower_head.size=3,3
192
+ errors.upper_head.line_color,errors.lower_head.line_color='royalblue','royalblue'
193
+
194
+ iPlot.add_layout(errors)
195
+ else:
196
+ iPlot=None
197
+
198
+ if return_raw==True:
199
+ return gPlot,rPlot,iPlot
200
+ else:
201
+ grid=gridplot([[gPlot,rPlot,iPlot]],width=400,height=400)
202
+ return grid
203
+
204
+ if __name__=='__main__':
205
+ plot=getLightCurve(245.4470133276900,-22.8862182469700)
206
+ show(plot)
File without changes
File without changes