3 import matplotlib
as mpl
5 import matplotlib
.pyplot
as plt
6 from matplotlib
.patches
import Rectangle
7 from matplotlib
.collections
import PatchCollection
8 from matplotlib
.transforms
import Affine2D
9 from mpl_toolkits
.mplot3d
import Axes3D
10 from matplotlib
.colors
import LinearSegmentedColormap
11 from mpl_toolkits
.basemap
import Basemap
13 from interpolation
import sort_dates
18 def create_pixels(lons
,lats
,widths
,heights
,alphas
,color
,label
):
20 Plot of pixels using centers (lons,lats), with sizes (widhts,heights), angle alphas, and color color.
22 :param lons: array of longitude coordinates at the center of the pixels
23 :param lats: array of latitude coordinates at the center of the pixels
24 :param widths: array of widhts of the pixels
25 :param heights: array of heights of the pixels
26 :param alphas: array of angles of the pixels
27 :param color: tuple with RGB color values
28 :return col: collection of rectangles with the pixels
30 Developed in Python 2.7.15 :: Anaconda 4.5.10, on MACINTOSH.
31 Angel Farguell (angel.farguell@gmail.com) 2018-12-28
36 for x
, y
, h
, w
, a
in zip(lons
, lats
, heights
, widths
, alphas
):
37 xpos
= x
- w
/2 # The x position will be half the width from the center
38 ypos
= y
- h
/2 # same for the y position, but with height
39 rect
= Rectangle( (xpos
, ypos
), w
, h
, a
) # Create a rectangle
40 pixels
.append(rect
) # Add the rectangle patch to our list
42 # Create a collection from the rectangles
43 col
= PatchCollection(pixels
)
44 # set the alpha for all rectangles
46 # Set the colors using the colormap
47 col
.set_facecolor( [color
]*len(lons
) )
49 col
.set_linewidth( 0 )
54 def basemap_scatter_mercator(g
,bounds
,bmap
,only_fire
=False):
56 Scatter plot of fire and ground pixels in a png file using a basemap with mercator projection
58 :param g: granule dictionary from read_*_files functions in JPSSD.py
59 :param bounds: array with the coordinates of the bounding box of the case
60 :param map: basemap mercator map where to plot the center of the pixels
61 :return png: string with png plot
62 :return float_bounds: coordinates of the borders of the png file
64 Developed in Python 2.7.15 :: Anaconda 4.5.10, on MACINTOSH.
65 Angel Farguell (angel.farguell@gmail.com) 2018-04-05
70 flon
= np
.ravel(g
.lon
)
71 flat
= np
.ravel(g
.lat
)
72 mask
= np
.ravel(g
.fire
)
74 fil
= np
.logical_and(np
.logical_and(np
.logical_and(flon
>= bounds
[0], flon
<= bounds
[1]), flat
>= bounds
[2]), flat
<= bounds
[3])
77 categories
= (np
.array(mask
[fil
] == 7), np
.array(mask
[fil
] == 8),
78 np
.array(mask
[fil
] == 9))
80 labels
= ('Fire low','Fire nominal','Fire high')
81 colors
= [(1,1,0),(1,.65,0),(.5,0,0)]
83 categories
= (np
.array(mask
[fil
] == 3), np
.array(mask
[fil
] == 5),
84 np
.array(mask
[fil
] == 7), np
.array(mask
[fil
] == 8),
85 np
.array(mask
[fil
] == 9))
86 alphas
= (.4,.4,.5,.6,.7)
87 labels
= ('Water','Ground','Fire low','Fire nominal','Fire high')
88 colors
= [(0,0,.5),(0,.5,0),(1,1,0),(1,.65,0),(.5,0,0)]
93 for i
,cat
in enumerate(categories
):
94 lon
.append(flon
[fil
][cat
])
95 lat
.append(flat
[fil
][cat
])
96 val
.append(np
.ones(lon
[i
].shape
)*i
)
99 fig
= plt
.figure(frameon
=False,figsize
=(12,8))
101 cmap
= LinearSegmentedColormap
.from_list('fire_detections', colors
, N
=N
)
103 bmap
.scatter(lon
[i
],lat
[i
],size
,c
=val
[i
],latlon
=True,marker
='.',cmap
=cmap
,vmin
=-.5,vmax
=N
-.5,alpha
=alphas
[i
],linewidths
=0)
105 str_io
= StringIO
.StringIO()
106 plt
.savefig(str_io
,bbox_inches
='tight',format
='png',pad_inches
=0,transparent
=True)
109 orientation
= 'vertical'
113 kwargs
= { 'norm': mpl
.colors
.Normalize(-.5,N
-.5),
114 'orientation': orientation
,
115 'spacing': 'proportional',
119 # build figure according to requested orientation
120 hsize
, wsize
= (size_in
,size_in
*0.5) if orientation
== 'vertical' else (size_in
*0.5,size_in
)
121 fig
= plt
.figure(figsize
=(wsize
,hsize
))
123 # proportions that work with axis title (horizontal not tested)
124 ax
= fig
.add_axes([.5,.03,.12,.8]) if orientation
=='vertical' else fig
.add_axes([0.03,.4,.8,.12])
126 # construct the colorbar and modify properties
127 cb
= mpl
.colorbar
.ColorbarBase(ax
,**kwargs
)
128 cb
.ax
.tick_params(length
=0)
129 cb
.ax
.set_yticklabels(labels
)
130 cb
.set_label(cb_label
,color
='0',fontsize
=8,labelpad
=-50)
132 # move ticks to left side
133 ax
.yaxis
.set_ticks_position('left')
134 for tick_lbl
in ax
.get_yticklabels():
135 tick_lbl
.set_color('0')
136 tick_lbl
.set_fontsize(5)
141 png
= str_io
.getvalue()
143 numpy_bounds
= [ (bounds
[0],bounds
[2]),(bounds
[1],bounds
[2]),(bounds
[1],bounds
[3]),(bounds
[0],bounds
[3]) ]
144 float_bounds
= [ (float(x
), float(y
)) for x
,y
in numpy_bounds
]
145 return png
, float_bounds
148 def center_pixels_plot(g
,bounds
):
150 Center pixels plot: generates a plot of the center of the pixels.
152 :param g: granule dictionary from read_*_files functions in JPSSD.py
153 :param bounds: array with the coordinates of the bounding box of the case
154 :return: 2D plot of the center of the pixels
156 Developed in Python 2.7.15 :: Anaconda 4.5.10, on MACINTOSH.
157 Angel Farguell (angel.farguell@gmail.com) 2018-12-28
161 ax
=fig
.add_subplot(111)
163 # Size of the center of the pixels
167 lons
=np
.array(g
.lon_nofire
)
168 lats
=np
.array(g
.lat_nofire
)
169 color
=(0,0.59765625,0)
170 plt
.scatter(lons
,lats
,size
,marker
='.',color
=color
,edgecolors
='k')
173 lons
=np
.array(g
.lon_fire
)
174 lats
=np
.array(g
.lat_fire
)
175 color
=(0.59765625,0,0)
176 plt
.scatter(lons
,lats
,size
,marker
='.',color
=color
,edgecolors
='k')
178 ax
.set_xlim(bounds
[0],bounds
[1])
179 ax
.set_ylim(bounds
[2],bounds
[3])
182 def pixels_plot(g
,bounds
):
184 Regular pixels plot: generates a plot of the pixels using a regular grid by distances.
186 :param g: granule dictionary from read_*_files functions in JPSSD.py
187 :param bounds: array with the coordinates of the bounding box of the case
188 :return: 2D plot of the pixels
190 Developed in Python 2.7.15 :: Anaconda 4.5.10, on MACINTOSH.
191 Angel Farguell (angel.farguell@gmail.com) 2018-12-28
203 dlonh
=np
.hstack((dlonh
,dlonh
[:,[-1]]))
205 dlonv
=np
.vstack((dlonv
,dlonv
[-1]))
212 dlath
=np
.hstack((dlath
,dlath
[:,[-1]]))
214 dlatv
=np
.vstack((dlatv
,dlatv
[-1]))
216 dh
=np
.sqrt(dlonh
**2+dlath
**2)
217 dv
=np
.sqrt(dlonv
**2+dlatv
**2)
219 # Mean between the distances
221 w
[:,1:-1]=np
.hstack([(dh
[:,[k
]]+dh
[:,[k
+1]])/2 for k
in range(dh
.shape
[1]-2)])
223 h
[1:-1,:]=np
.vstack([(dv
[k
]+dv
[k
+1])/2 for k
in range(dv
.shape
[0]-2)])
226 # Maximum between the distances
228 w[:,1:-1]=np.hstack([np.maximum(dh[:,[k]],dh[:,[k+1]]) for k in range(dh.shape[1]-2)])
230 h[1:-1,:]=np.vstack([np.maximum(dv[k],dv[k+1]) for k in range(dv.shape[0]-2)])
233 angle
=np
.arctan(dlath
/dlonh
)*180/np
.pi
238 ax
= fig
.gca(projection
='3d')
239 surf
= ax
.plot_surface(lon
,lat
,w
)
241 ax
= fig
.gca(projection
='3d')
242 surf
= ax
.plot_surface(lon
,lat
,h
)
244 ax
= fig
.gca(projection
='3d')
245 surf
= ax
.plot_surface(lon
,lat
,angle
)
249 fil
=np
.logical_and(np
.logical_and(np
.logical_and(flon
>= bounds
[0], flon
<= bounds
[1]), flat
>= bounds
[2]), flat
<= bounds
[3])
255 nofi
=np
.logical_or(ffg
== 3, ffg
== 5)
258 width
=np
.ravel(w
)[fil
]
259 height
=np
.ravel(h
)[fil
]
260 alpha
=np
.ravel(angle
)[fil
]
263 ax
= fig
.add_subplot(111)
271 color
=(0,0.59765625,0)
272 col_nofire
=create_pixels(lons
,lats
,widths
,heights
,alphas
,color
,'Ground')
273 ax
.add_collection(col_nofire
)
281 color
=(0.59765625,0,0)
282 col_fire
=create_pixels(lons
,lats
,widths
,heights
,alphas
,color
,'Fire')
283 ax
.add_collection(col_fire
)
286 ax
.set_xlim(bounds
[0],bounds
[1])
287 ax
.set_ylim(bounds
[2],bounds
[3])
290 def create_kml(kml_data
,kml_path
):
292 Creation of KML file with png files from basemap_scatter_mercator function
294 :param kml_data: dictionary with granules to plot information: name, png_file, bounds, time
295 :param kml_path: path to kml to generate
297 Developed in Python 2.7.15 :: Anaconda 4.5.10, on MACINTOSH.
298 Angel Farguell (angel.farguell@gmail.com) 2018-04-05
301 with
open(kml_path
,'w') as kml
:
302 kml
.write("""<?xml version="1.0" encoding="UTF-8"?>\n""")
303 kml
.write("""<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">\n""")
304 kml
.write("""<Document><name>Observed Data</name>""")
307 <name>Overlays</name>""")
308 for idx
,data
in enumerate(kml_data
):
311 png
= data
['png_file']
312 bounds
= data
['bounds']
313 coord
= (str(bounds
[0]),str(bounds
[2]),
314 str(bounds
[1]),str(bounds
[2]),
315 str(bounds
[1]),str(bounds
[3]),
316 str(bounds
[0]),str(bounds
[3]),
317 str(bounds
[0]),str(bounds
[2]))
321 <Icon><href>%s</href></Icon>
322 <gx:TimeStamp><when>%s</when></gx:TimeStamp>""" % (
333 </gx:LatLonQuad>""" % coord
)
338 kml
.write("""</Document>\n</kml>\n""")
340 print 'Created file %s' % kml_path
344 print "Error: python %s pixel_plot_type" % sys
.argv
[0]
345 print " - Center pixels in basemap: 0"
346 print " - Center pixels plot: 1"
347 print " - Regular pixels plot: 2"
349 if __name__
== "__main__":
354 if sys
.argv
[1] not in ['0','1','2']:
356 print "Invalid value given: %s" % sys
.argv
[1]
361 print 'Loading data...'
362 data
,fxlon
,fxlat
,time_num
=sl
.load('data')
364 print "Error: No data file in the directory. First run a case using case.py."
367 granules
=sort_dates(data
)
368 bounds
=[fxlon
.min(),fxlon
.max(),fxlat
.min(),fxlat
.max()]
370 print 'Plotting data...'
372 if sys
.argv
[1] is '0':
373 m
= Basemap(projection
='merc',llcrnrlat
=bounds
[2], urcrnrlat
=bounds
[3], llcrnrlon
=bounds
[0], urcrnrlon
=bounds
[1])
375 for idx
, g
in enumerate(granules
):
376 raster_png_data
,corner_coords
= basemap_scatter_mercator(g
[1],bounds
,m
)
377 bounds
= (corner_coords
[0][0],corner_coords
[1][0],corner_coords
[0][1],corner_coords
[2][1])
378 pngfile
= g
[0]+'.png'
379 timestamp
= g
[1].acq_date
+ 'T' + g
[1].acq_time
[0:2] + ':' + g
[1].acq_time
[2:4] + 'Z'
380 with
open(pngfile
, 'w') as f
:
381 f
.write(raster_png_data
)
382 print '> File %s saved.' % g
[0]
383 kmld
.append(Dict({'name': g
[0], 'png_file': pngfile
, 'bounds': bounds
, 'time': timestamp
}))
384 create_kml(kmld
,'./doc.kml')
385 os
.system('zip -r granules.kmz doc.kml *.png')
386 print 'Created file granules.kmz'
387 os
.system('rm doc.kml *_A*_*.png')
388 elif sys
.argv
[1] is '1':
390 center_pixels_plot(g
[1],bounds
)
391 plt
.title('Granule %s' % g
[0])
395 pixels_plot(g
[1],bounds
)
396 plt
.title('Granule %s' % g
[0])