def pipeline_for_dataset(self, d, panels): # Set up dataset -> time-height bound filter -> brancher branch = Branchpoint([]) brancher = branch.broadcast() # strictly speaking, z in the map projection and MSL alt aren't the same - z is somewhat distorted by the projection. # therefore, add some padding. filtered again later after projection. quality_filter = BoundsFilter(target=brancher, bounds=self.bounds).filter() transform_mapping = {'z':('alt', (lambda v: (v[0]*1.0e3 - 1.0e3, v[1]*1.0e3 + 1.0e3)) ) } bound_filter = BoundsFilter(target=quality_filter, bounds=panels.bounds, restrict_to=('time'), transform_mapping=transform_mapping) filterer = bound_filter.filter() d.target = filterer # Set up brancher -> coordinate transform -> final_filter -> mutli-axis scatter updater scatter_ctrl = PanelsScatterController( panels=panels, color_field='time', default_color_bounds=self.default_color_bounds) scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() final_bound_filter = BoundsFilter(target=scatter_updater, bounds=panels.bounds) final_filterer = final_bound_filter.filter() cs_transformer = panels.cs.project_points( target=final_filterer, x_coord='x', y_coord='y', z_coord='z', lat_coord='lat', lon_coord='lon', alt_coord='alt', distance_scale_factor=1.0e-3) branch.targets.add(cs_transformer) # return each broadcaster so that other things can tap into results of transformation of this dataset return branch, scatter_ctrl
def flash_size_stats_for_intervals(t_start, t_end, dt, lat_bounds=None, lon_bounds=None, outdir=None): """ Create a pipeline to process an arbitrary number of flashes which are accumulated in dt-length intervals between t_start and t_end. t_start, t_end: datetime.datetime instances dt: datetime.timedelta Returns: printer_of_stats: all_frame_targets: a list of targets that receive (events, flashes) from the flash file reader all_frame_targets can be passed as other_analysis_targets to lmatools.flash_stats.plot_spectra_for_files. When all data have been read (i.e., plot_spectra_for_files has returned), the accumulated statistics are retrieved by closing the targets returned by this function, i.e. for target in timeframe_targets: target.close() printer_of_stats.close() plot_spectra_for_files itself could be refactored to make use of these same time windows natively, but that's a project for later. The dependency here on stormdrain is another issue; it may make sense to have lmatools depend on stormdrain. """ t_edges, duration = time_edges(t_start, t_end, dt.total_seconds()) t_ref, t_edges_seconds = seconds_since_start_of_day(t_start, t_edges) n_frames = len(t_edges) - 1 results = StatResults(basedate=t_ref, outdir=outdir) printer_of_stats = results.stats_printer() all_frame_targets = [] for n in range(n_frames): # New BoundsFilter object for filtering flashes and flash_stats.stats_for_parameter that sits behind the bounds filter t0, t1 = t_edges_seconds[n:n + 2] b = Bounds() if lat_bounds is not None: b.ctr_lat = lat_bounds if lon_bounds is not None: b.ctr_lon = lon_bounds b.start = t0, t1 statframer = results.stats_for_frame(t_edges[n], t_edges[n + 1], target=printer_of_stats) momentizer = raw_moments_for_parameter('area', preprocess=np.sqrt, output_target=statframer) bound_filt = BoundsFilter(bounds=b, target=momentizer) ev_fl_rcvr = events_flashes_receiver(target=bound_filt.filter()) all_frame_targets.append(ev_fl_rcvr) return printer_of_stats, all_frame_targets
def pipeline_for_dataset(self, d, panels, names4d=('lon', 'lat', 'alt', 'time'), transform_mapping=None, scatter_kwargs = {} ): """ Set 4d_names to the spatial coordinate names in d that provide longitude, latitude, altitude, and time. Default of lon, lat, alt, and time which are assumed to be in deg, deg, meters, seconds entries in the scatter_kwargs dictionary are passed as kwargs to the matplotlib scatter call. """ # Set up dataset -> time-height bound filter -> brancher branch = Branchpoint([]) brancher = branch.broadcast() # strictly speaking, z in the map projection and MSL alt aren't the same - z is somewhat distorted by the projection. # therefore, add some padding. filtered again later after projection. quality_filter = BoundsFilter(target=brancher, bounds=self.bounds).filter() if transform_mapping is None: transform_mapping = self.z_alt_mapping # Use 'time', which is the name in panels.bounds, and not names4d[3], which should # is linked to 'time' by transform_mapping if necessary bound_filter = BoundsFilter(target=quality_filter, bounds=panels.bounds, restrict_to=('time'), transform_mapping=transform_mapping) filterer = bound_filter.filter() d.target = filterer # Set up brancher -> coordinate transform -> final_filter -> mutli-axis scatter updater scatter_ctrl = PanelsScatterController( panels=panels, color_field=names4d[3], default_color_bounds=self.default_color_bounds, **scatter_kwargs) scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() final_bound_filter = BoundsFilter(target=scatter_updater, bounds=panels.bounds) final_filterer = final_bound_filter.filter() cs_transformer = panels.cs.project_points( target=final_filterer, x_coord='x', y_coord='y', z_coord='z', lat_coord=names4d[1], lon_coord=names4d[0], alt_coord=names4d[2], distance_scale_factor=1.0e-3) branch.targets.add(cs_transformer) # return each broadcaster so that other things can tap into results of transformation of this dataset return branch, scatter_ctrl
def flash_size_stats_for_intervals(t_start, t_end, dt, lat_bounds=None, lon_bounds=None, outdir=None): """ Create a pipeline to process an arbitrary number of flashes which are accumulated in dt-length intervals between t_start and t_end. t_start, t_end: datetime.datetime instances dt: datetime.timedelta Returns: printer_of_stats: all_frame_targets: a list of targets that receive (events, flashes) from the flash file reader all_frame_targets can be passed as other_analysis_targets to lmatools.flash_stats.plot_spectra_for_files. When all data have been read (i.e., plot_spectra_for_files has returned), the accumulated statistics are retrieved by closing the targets returned by this function, i.e. for target in timeframe_targets: target.close() printer_of_stats.close() plot_spectra_for_files itself could be refactored to make use of these same time windows natively, but that's a project for later. The dependency here on stormdrain is another issue; it may make sense to have lmatools depend on stormdrain. """ t_edges, duration = time_edges(t_start, t_end, dt.total_seconds()) t_ref, t_edges_seconds = seconds_since_start_of_day(t_start, t_edges) n_frames = len(t_edges)-1 results = StatResults(basedate=t_ref, outdir=outdir) printer_of_stats = results.stats_printer() all_frame_targets = [] for n in range(n_frames): # New BoundsFilter object for filtering flashes and flash_stats.stats_for_parameter that sits behind the bounds filter t0, t1 = t_edges_seconds[n:n+2] b = Bounds() if lat_bounds is not None: b.ctr_lat = lat_bounds if lon_bounds is not None: b.ctr_lon = lon_bounds b.start = t0, t1 statframer = results.stats_for_frame(t_edges[n], t_edges[n+1], target=printer_of_stats) momentizer = raw_moments_for_parameter('area', preprocess=np.sqrt, output_target=statframer) bound_filt = BoundsFilter(bounds=b, target=momentizer) ev_fl_rcvr = events_flashes_receiver(target=bound_filt.filter()) all_frame_targets.append(ev_fl_rcvr) return printer_of_stats, all_frame_targets
def plot_demo_dataset(d, panels): # Create a scatterplot representation of the dataset, and add the necessary transforms # to get the data to the plot. In this case, it's a simple filter on the plot bounds, and # distribution to all the scatter artists. Might also add map projection here if the plot # were not directly showing lat, lon, alt. # Set up dataset -> time-height bound filter -> brancher branch = Branchpoint([]) brancher = branch.broadcast() # strictly speaking, z in the map projection and MSL alt aren't the same - z is somewhat distorted by the projection. # therefore, add some padding. filtered again later after projection. transform_mapping = {'z':('alt', (lambda v: (v[0]*1.0e3 - 1.0e3, v[1]*1.0e3 + 1.0e3)) ) } bound_filter = BoundsFilter(target=brancher, bounds=panels.bounds, restrict_to=('time'), transform_mapping=transform_mapping) filterer = bound_filter.filter() d.target = filterer # Set up brancher -> coordinate transform -> final_filter -> mutli-axis scatter updater scatter_ctrl = PanelsScatterController(panels=panels, color_field='time') scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() final_bound_filter = BoundsFilter(target=scatter_updater, bounds=panels.bounds) final_filterer = final_bound_filter.filter() cs_transformer = panels.cs.project_points(target=final_filterer, x_coord='x', y_coord='y', z_coord='z', lat_coord='lat', lon_coord='lon', alt_coord='alt', distance_scale_factor=1.0e-3) branch.targets.add(cs_transformer) # return each broadcaster so that other things can tap into results of transformation of this dataset return branch, scatter_outlet_broadcaster
def plot_demo_dataset(d, panels): # Create a scatterplot representation of the dataset, and add the necessary transforms # to get the data to the plot. In this case, it's a simple filter on the plot bounds, and # distribution to all the scatter artists. Might also add map projection here if the plot # were not directly showing lat, lon, alt. # Set up dataset -> time-height bound filter -> brancher branch = Branchpoint([]) brancher = branch.broadcast() # strictly speaking, z in the map projection and MSL alt aren't the same - z is somewhat distorted by the projection. # therefore, add some padding. filtered again later after projection. transform_mapping = {"z": ("alt", (lambda v: (v[0] * 1.0e3 - 1.0e3, v[1] * 1.0e3 + 1.0e3)))} bound_filter = BoundsFilter( target=brancher, bounds=panels.bounds, restrict_to=("time"), transform_mapping=transform_mapping ) filterer = bound_filter.filter() d.target = filterer # Set up brancher -> coordinate transform -> final_filter -> mutli-axis scatter updater scatter_ctrl = PanelsScatterController(panels=panels, color_field="time") scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() final_bound_filter = BoundsFilter(target=scatter_updater, bounds=panels.bounds) final_filterer = final_bound_filter.filter() cs_transformer = panels.cs.project_points( target=final_filterer, x_coord="x", y_coord="y", z_coord="z", lat_coord="lat", lon_coord="lon", alt_coord="alt", distance_scale_factor=1.0e-3, ) branch.targets.add(cs_transformer) # return each broadcaster so that other things can tap into results of transformation of this dataset return branch, scatter_outlet_broadcaster
def pipeline_for_dataset(self, d, panels, marker='s'): # Set up dataset -> time-height bound filter -> brancher branch = Branchpoint([]) brancher = branch.broadcast() # strictly speaking, z in the map projection and MSL alt aren't the same - z is somewhat distorted by the projection. # therefore, add some padding. filtered again later after projection. # quality_filter = BoundsFilter(target=brancher, bounds=self.bounds).filter() transform_mapping = {'z':('alt', (lambda v: (v[0]*1.0e3 - 1.0e3, v[1]*1.0e3 + 1.0e3)) ) } # make the target in the line below quality_filter to add additional data-dependent # filtering. bound_filter = BoundsFilter(target=brancher, bounds=panels.bounds, restrict_to=('time'), transform_mapping=transform_mapping) filterer = bound_filter.filter() # Adjust the height in response to bounds changes, so that the markers stay near # the bottom axis in a time-height view height_control = GroundMarkerHeightController(target=filterer, alt_name='alt') height_adjuster = height_control.adjust_height() d.target = height_adjuster # Set up brancher -> coordinate transform -> final_filter -> mutli-axis scatter updater scatter_ctrl = PanelsScatterController( panels=panels, s=64, color_field='time', marker=marker) #default_color_bounds=self.default_color_bounds) scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() final_bound_filter = BoundsFilter(target=scatter_updater, bounds=panels.bounds) final_filterer = final_bound_filter.filter() cs_transformer = panels.cs.project_points( target=final_filterer, x_coord='x', y_coord='y', z_coord='z', lat_coord='lat', lon_coord='lon', alt_coord='alt', distance_scale_factor=1.0e-3) branch.targets.add(cs_transformer) # return each broadcaster so that other things can tap into results of transformation of this dataset return branch, scatter_ctrl
# Create a dataset that stores numpy named array data, and automatically receives updates # when the bounds of a plot changes. d = NamedArrayDataset(data) # Create a scatterplot representation of the dataset, and add the necessary transforms # to get the data to the plot. In this case, it's a simple filter on the plot bounds, and # distribution to all the scatter artists. Might also add map projection here if the plot # were not directly showing lat, lon, alt. scatter_ctrl = PanelsScatterController(panels=panels, color_field='time') scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() branch = Branchpoint([ scatter_updater, ]) brancher = branch.broadcast() bound_filter = BoundsFilter(target=brancher, bounds=panels.bounds) filterer = bound_filter.filter() d.target = filterer # Set an initial view. panels.panels['xy'].axis((-110, -90, 30, 40)) panels.panels['tz'].axis((0, 10, 0, 5e3)) # Shouldn't need these, since the previous two cover all coordinates # panels.panels['zy'].axis((0, 5e3, 30, 40,)) # panels.panels['xz'].axis((-110, -90, 0, 5e3)) # Now let's set up a second figure that has projected data. The unprojected axes act # as the master data controller, and control what data get re-flowed to the other plot. panel2_fig = plt.figure() panels2 = Panels4D(figure=panel2_fig, names_4D=('x', 'y', 'z', 'time'))
dtype = [ ('name', '|S32'), ('lat', '>f4'), ('lon', '>f4'), ('alt', '>f4'), ('time', '>f4') ] ) # Create a dataset that stores numpy named array data, and automatically receives updates # when the bounds of a plot changes. d = NamedArrayDataset(data) # Create a scatterplot representation of the dataset, and add the necessary transforms # to get the data to the plot. In this case, it's a simple filter on the plot bounds, and # distribution to all the scatter artists. Might also add map projection here if the plot # were not directly showing lat, lon, alt. scatter_ctrl = PanelsScatterController(panels=panels, color_field='time') scatter_outlet_broadcaster = scatter_ctrl.branchpoint scatter_updater = scatter_outlet_broadcaster.broadcast() branch = Branchpoint([scatter_updater,]) brancher = branch.broadcast() bound_filter = BoundsFilter(target=brancher, bounds=panels.bounds) filterer = bound_filter.filter() d.target = filterer # Set an initial view. panels.panels['xy'].axis((-110, -90, 30, 40)) panels.panels['tz'].axis((0, 10, 0, 5e3)) # Shouldn't need these, since the previous two cover all coordinates # panels.panels['zy'].axis((0, 5e3, 30, 40,)) # panels.panels['xz'].axis((-110, -90, 0, 5e3)) # Now let's set up a second figure that has projected data. The unprojected axes act # as the master data controller, and control what data get re-flowed to the other plot.