In [13]:
%%bash
# ls -lh /data/KTAL/Ka2/20150629/raw/

In [2]:
import pyart
import numpy as np

In [4]:
radar=pyart.io.read_sigmet('/data/KTAL/Ka2/20150629/raw/Ka2150629221426.RAW7A3V')
# print radar.latitude, radar.longitude, radar.altitude

In [5]:
from IPython.html import widgets 
from IPython.display import display


:0: FutureWarning: IPython widgets are experimental and may change in the future.

In [6]:
import netCDF4

def diagnose_sweep_time_range(radar):
    units = radar.time['units']
    calendar = radar.time['calendar']
    times = [radar.time['data'][sl] for sl in radar.iter_slice()]
    swp_start_times = [netCDF4.num2date(t.min(), units, calendar) for t in times]
    swp_end_times = [netCDF4.num2date(t.max(), units, calendar) for t in times]
    return swp_start_times, swp_end_times

def diagnose_vcp(radar):
    # swp_start = radar.sweep_start_ray_index['data']
    # swp_end = radar.sweep_end_ray_index['data']+1
    if 'ppi' in radar.scan_type.lower():
        angles = [np.median(el) for el in radar.iter_elevation()]
    else:
        angles = [np.median(az) for az in radar.iter_azimuth()]
    return angles

In [7]:
import matplotlib.pyplot as plt

field_range_defaults_ka = {
    'reflectivity':[-32,32],
    'velocity':[-12.9,12.9],
    'spectrum_width':[0.0,1.0],
    'total_power':[-30, 40]
}
field_range_defaults = field_range_defaults_ka
        
class RadarSelection(object):
    def __init__(self, radar, sweep_id=0, field_id='reflectivity'):
        """ This class is used by the RadarWidget, which has an interface for
            selecting a sweep, to maintain the current selected radar data.
        
            It decouples the radar widget view from the data selection operation
            so that radar data can be selected programmatically as well.
        """
        
        self.radar=radar
        self._field_range_history = field_range_defaults.copy()
        
        self.sweep_id = sweep_id
        self.field_id = field_id
        self.field_range = self._field_range_history[field_id]

    def __str__(self):
        rep = "{0}, {1}, {2}".format(self.field_id, self.field_range, self.sweep_id)
        return rep

    @property
    def sweep_id(self):
        return self._sweep_id

    @sweep_id.setter
    def sweep_id(self, value):
        self._sweep_id = int(value)


    @property
    def field_id(self):
        return self._field_id

    @field_id.setter
    def field_id(self, value):
        self._field_id = value
        try:
            self.field_range = self._field_range_history[self._field_id]
        except KeyError:
            print "No default range for field {0}. Setting to a wide range.".format(value)
            self.field_range = [-100.0, 100.0]



    @property
    def field_range(self):
        return self._field_range

    @field_range.setter
    def field_range(self, value):
        if len(value) <> 2:
            raise ValueError, "Must be two values in range."
        self._field_range = value
        self._field_range_history[self.field_id] = self._field_range


class RadarWidget(object):
    def __init__(self, radar, on_scan_changed=None):
        """ Expects a PyART radar object"""
        
        self.on_scan_changed = on_scan_changed
        
        self.radar=radar
        self.radar_selection = RadarSelection(self.radar)
        self.__make_location_widget()
        self.__make_sweep_stats_widget()
        self.__make_scan_select_widget()
        
        self.__make_master_widget()
        self.update()
        self.scan_changed()
        
    def __make_master_widget(self):        
        row0 = (self.w_location, 
                self.w_stats,
               )
        row1 = (self.w_scan_select,
               )
        self.w_location.width = '50%'
        self.w_stats.width = '50%'
        self.w_scan_select.width = '50%'
                    
        w_row0 = widgets.HBox(children=row0)
        w_row1 = widgets.HBox(children=row1)

        children = (w_row0, w_row1)
        self.master_widget = widgets.VBox(children = children)
        
    def scan_changed(self, defer=False):
        if defer == False:
            if self.on_scan_changed is not None:
                self.on_scan_changed()

    def update(self):
        """ Refresh data in boxes from radar object """
        self._update_location_widget()
        self._update_sweep_stats_widget()
        self._update_scan_select_widget()
        self.radar_selection.field_id = self.w_field_choice.value
        self.w_field_min.value, self.w_field_max.value = self.radar_selection.field_range
#         self.radar_selection.field_range = [self.w_field_min.value, self.w_field_max.value]


    # ----- Location  -----
    
    def _update_location_widget(self):
        self.w_ctrlon.value = self.radar.longitude['data'][0]
        self.w_ctrlat.value = self.radar.latitude['data'][0]
        self.w_ctralt.value = self.radar.altitude['data'][0]
        
    def _radar_location_changed(self):
        self.radar.longitude['data'][0] = self.w_ctrlon.value
        self.radar.latitude['data'][0] = self.w_ctrlat.value
        self.radar.altitude['data'][0] = self.w_ctralt.value
        
    def __make_location_widget(self):
        self.w_ctrlon = widgets.FloatText(description='Lon')
        self.w_ctrlat = widgets.FloatText(description='Lat')
        self.w_ctralt = widgets.FloatText(description='Alt')

        children = (self.w_ctrlon, self.w_ctrlat, self.w_ctralt)
        self.w_location = widgets.VBox(children = children)

    # ----- Info box / stats readout -----
    
    def _update_sweep_stats_widget(self):
        metadata = "Gates: {0}, Rays: {1}, Sweeps: {2} \nScan Type: {3}, {4}\nBeamwidth: {5}"
        
        stats = metadata.format(
                    self.radar.ngates, self.radar.nrays, self.radar.nsweeps,
                    self.radar.scan_type, self.radar.sweep_mode['data'][0], 
                    self.radar.instrument_parameters['radar_beam_width_h']['data'][0])
        self.w_sweep_stats.value = stats
        
    def __make_sweep_stats_widget(self):
        self.w_sweep_stats = widgets.Textarea()
        
        children = (self.w_sweep_stats,)
        self.w_stats = widgets.Box(children = children)

    # ----- Scan Selection Parameters -----
        
    def _update_scan_select_widget(self, time_format = '%H%M:%S'):
        self.w_field_choice.options = self.radar.fields.keys()
        vcp = diagnose_vcp(self.radar)
        starts, ends = diagnose_sweep_time_range(self.radar)
        angles = [u'{0}: {1:6.2f}°, {2} - {3}'.format(ai, ang, 
                                                      t0.strftime(time_format), 
                                                      t1.strftime(time_format)) 
                  for ai, (ang, t0, t1) in enumerate(zip(vcp, starts, ends))]
#         angles = [str(ang) for ang in diagnose_vcp(ka1)]
        self.w_angle_choice.options = angles

    
    def _scan_selected(self, name, value):
        swp_id = int(value.split(':')[0])
        self.radar_selection.sweep_id = swp_id
        self.scan_changed()
    def _field_selected(self, name, value):
        self.radar_selection.field_id = value
        self.w_field_min.value = self.radar_selection.field_range[0]
        self.w_field_max.value = self.radar_selection.field_range[1]
        self.scan_changed()
    def _range_min_changed(self, name, value):
        self.radar_selection.field_range[0] = value
        self.scan_changed(defer=True)
    def _range_max_changed(self, name, value):
        self.radar_selection.field_range[1] = value
        self.scan_changed(defer=True)
    def __make_scan_select_widget(self):
        self.w_field_choice = widgets.Select(description='Field') 
        self.w_field_min  = widgets.FloatText(description = 'Range')
        self.w_field_max  = widgets.FloatText()
        self.w_field_range_box = widgets.HBox(children=(self.w_field_min, self.w_field_max))
        self.w_angle_choice = widgets.Select(description='Angle')
        
        self.w_angle_choice.on_trait_change(self._scan_selected, 'value')
        self.w_field_choice.on_trait_change(self._field_selected, 'value')
        self.w_field_min.on_trait_change(self._range_min_changed, 'value')
        self.w_field_max.on_trait_change(self._range_max_changed, 'value')

        children = (widgets.VBox(children=(self.w_field_choice,
                                           self.w_field_range_box)),
                    self.w_angle_choice)
        self.w_scan_select = widgets.HBox(children = children)

In [8]:
class RadarSweepView(object):
    def __init__(self, radar_selection):
        self.radar_selection = radar_selection
        self.fig = plt.figure()
        self.display = pyart.graph.RadarDisplay(self.radar_selection.radar)
        plt.show(block=False)        
    def update(self):
        self.fig.clf()
        field_range = self.radar_selection.field_range
        field_id = self.radar_selection.field_id
        sweep_id = self.radar_selection.sweep_id
        self.display.plot(field_id, sweep=sweep_id, 
                          vmin=field_range[0], vmax=field_range[1],
                          fig = self.fig)
        self.fig.canvas.draw()

class RadarSweepViewWidget(object):
    def __init__(self, radar_sweep_view):
        self.radar_sweep_view = radar_sweep_view
        self.w_draw_widget = widgets.Button(description='Draw')
        self.w_draw_widget.on_click(self.update)
        children = (self.w_draw_widget,)
        self.master_widget = widgets.HBox(children=children)
    def update(self, value):
        self.radar_sweep_view.update()

radar_widget = RadarWidget(radar)
view = RadarSweepView(radar_widget.radar_selection)
view_widget = RadarSweepViewWidget(view)
radar_widget.on_scan_changed = view.update
display(radar_widget.master_widget)
display(view_widget.master_widget)
view.update()


No default range for field normalized_coherent_power. Setting to a wide range.
No default range for field total_power. Setting to a wide range.

In [16]:
view.update()

In [ ]:


In [ ]: