def _visdata(self): self._setcolors() datasets = [] if isinstance(pytplot.data_quants[self.tvar_name].data, list): for oplot_name in pytplot.data_quants[self.tvar_name].data: datasets.append(pytplot.data_quants[oplot_name]) else: datasets.append(pytplot.data_quants[self.tvar_name]) for dataset in datasets: #Get Linestyle line_style = None if 'linestyle' in pytplot.data_quants[self.tvar_name].extras: line_style = pytplot.data_quants[ self.tvar_name].extras['linestyle'] #Get a list of formatted times corrected_time = [] for x in dataset.data.index: corrected_time.append(tplot_utilities.int_to_str(x)) #Bokeh uses milliseconds since epoch for some reason x = dataset.data.index * 1000 #Create lines from each column in the dataframe for column_name in dataset.data.columns: y = dataset.data[column_name] if self._getyaxistype() == 'log': y.loc[y <= 0] = np.NaN line_source = ColumnDataSource( data=dict(x=x, y=y, corrected_time=corrected_time)) if self.auto_color: line = Line(x='x', y='y', line_color=self.colors[self.linenum % len(self.colors)], **pytplot.data_quants[self.tvar_name].line_opt) else: line = Line(x='x', y='y', **pytplot.data_quants[self.tvar_name].line_opt) if 'line_style' not in pytplot.data_quants[ self.tvar_name].line_opt: if line_style is not None: line.line_dash = line_style[self.linenum % len(line_style)] else: line.line_dash = pytplot.data_quants[ self.tvar_name].line_opt['line_style'] self.lineglyphs.append(self.fig.add_glyph(line_source, line)) self.linenum += 1
def _visdata(self): self._setcolors() x = pytplot.data_quants[self.tvar_name].data.index.tolist() temp = [ a for a in x if (a <= (pytplot.tplot_opt_glob['x_range'][1]) and a >= (pytplot.tplot_opt_glob['x_range'][0])) ] x = temp #Sometimes X will be huge, we'll need to cut down so that each x will stay about 1 pixel in size step_size = 1 num_rect_displayed = len(x) if (self.fig.plot_width) < num_rect_displayed: step_size = int( math.floor(num_rect_displayed / (self.fig.plot_width))) x[:] = x[0::step_size] #Determine bin sizes if pytplot.data_quants[self.tvar_name].spec_bins is not None: bins = pytplot.data_quants[self.tvar_name].spec_bins bins_vary = pytplot.data_quants[ self.tvar_name].spec_bins_time_varying bins_increasing = pytplot.data_quants[ self.tvar_name].spec_bins_ascending else: bins = pd.DataFrame( np.arange(len(pytplot.data_quants[ self.tvar_name].data.columns))).transpose() bins_vary = False bins_increasing = True #Get length of arrays size_x = len(x) size_y = len(bins.columns) #These arrays will be populated with data for the rectangle glyphs color = [] bottom = [] top = [] left = [] right = [] value = [] corrected_time = [] #left, right, and time do not depend on the values in spec_bins for j in range(size_x - 1): left.append(x[j] * 1000) right.append(x[j + 1] * 1000) corrected_time.append(tplot_utilities.int_to_str(x[j])) left = left * (size_y - 1) right = right * (size_y - 1) corrected_time = corrected_time * (size_y - 1) #Handle the case of time-varying bin sizes if bins_vary: temp_bins = bins.loc[x[0:size_x - 1]] else: temp_bins = bins.loc[0] if bins_increasing: bin_index_range = range(0, size_y - 1, 1) else: bin_index_range = range(size_y - 1, 0, -1) for i in bin_index_range: temp = pytplot.data_quants[self.tvar_name].data[i][x[0:size_x - 1]].tolist() value.extend(temp) color.extend( tplot_utilities.get_heatmap_color(color_map=self.colors[0], min_val=self.zmin, max_val=self.zmax, values=temp, zscale=self.zscale)) #Handle the case of time-varying bin sizes if bins_vary: bottom.extend(temp_bins[i].tolist()) if bins_increasing: top.extend(temp_bins[i + 1].tolist()) else: top.extend(temp_bins[i - 1].tolist()) else: bottom.extend([temp_bins[i]] * (size_x - 1)) if bins_increasing: top.extend([temp_bins[i + 1]] * (size_x - 1)) else: top.extend([temp_bins[i - 1]] * (size_x - 1)) #Here is where we add all of the rectangles to the plot cds = ColumnDataSource(data=dict(x=left, y=bottom, right=right, top=top, z=color, value=value, corrected_time=corrected_time)) self.fig.quad(bottom='y', left='x', right='right', top='top', color='z', source=cds) if self.interactive: if 'y_axis_type' in pytplot.data_quants[self.tvar_name].yaxis_opt: y_interactive_log = 'log' else: y_interactive_log = 'linear' self.interactive_plot = Figure(plot_height=self.fig.plot_height, plot_width=self.fig.plot_width, y_range=(self.zmin, self.zmax), y_axis_type=y_interactive_log) self.interactive_plot.min_border_left = 100 spec_bins = bins flux = [0] * len(spec_bins) interactive_line_source = ColumnDataSource( data=dict(x=spec_bins, y=flux)) interactive_line = Line(x='x', y='y') self.interactive_plot.add_glyph(interactive_line_source, interactive_line) self.callback = CustomJS(args=dict( cds=cds, interactive_line_source=interactive_line_source), code=""" var geometry = cb_data['geometry']; var x_data = geometry.x; // current mouse x position in plot coordinates var y_data = geometry.y; // current mouse y position in plot coordinates var d2 = interactive_line_source.get('data'); var asdf = cds.get('data'); var j = 0; x=d2['x'] y=d2['y'] time=asdf['x'] energies=asdf['y'] flux=asdf['value'] for (i = 0; i < time.length-1; i++) { if(x_data >= time[i] && x_data <= time[i+1] ) { x[j] = energies[i] y[j] = flux[i] j=j+1 } } j=0 interactive_line_source.trigger('change'); """)
def static2dplot(var, time): """ If the static option is set in tplot, and is supplied with a time, then the spectrogram plot(s) for which it is set will have another window pop up, with y and z values plotted at the specified time. """ # Grab names of data loaded in as tplot variables. names = list(pytplot.data_quants.keys()) # Get data we'll actually work with here. valid_variables = tplot_utilities.get_data(names) # Don't plot anything unless we have spectrograms with which to work. if valid_variables: # Get z label labels = tplot_utilities.get_labels_axis_types(names) # Put together data in easy-to-access format for plots. data = {} for name in valid_variables: bins = tplot_utilities.get_bins(name) time_values, z_values = tplot_utilities.get_z_t_values(name) data[name] = [bins, z_values, time_values] # Set up the 2D static plot pytplot.static_window = pg.GraphicsWindow() pytplot.static_window.resize(1000, 600) pytplot.static_window.setWindowTitle('Static Window') plot = pytplot.static_window.addPlot(title='2D Static Plot', row=0, col=0) # Make it so that whenever this first starts up, you just have an empty plot plot_data = plot.plot([], []) if var in valid_variables: # Get min/max values of data's time range (in both datetime and seconds since epoch) t_min = np.nanmin(time_values) t_min_str = tplot_utilities.int_to_str(np.nanmin(time_values)) t_min_conv_back = tplot_utilities.str_to_int(t_min_str) t_max = np.nanmax(time_values) t_max_str = tplot_utilities.int_to_str(np.nanmax(time_values)) t_max_conv_back = tplot_utilities.str_to_int(t_max_str) # Convert user input to seconds since epoch user_time = tplot_utilities.str_to_int(time) # Covering situation where user entered a time not in the dataset! # As long as they used a time in the dataset, this will not trigger. if user_time not in range(t_min_conv_back, t_max_conv_back + 1): while True: try: user_time = tplot_utilities.str_to_int( input( 'Chosen time not in range of data [{} to {}]. Input new time (%Y-%m-%d %H:%M:%S). ' .format(t_min_str, t_max_str))) except: continue else: if user_time not in range(int(t_min), int(t_max)): continue else: break # Get time closest to the user's time choice time_array = np.array(data[var][2]) array = np.asarray(time_array) idx = (np.abs(array - user_time)).argmin() # If user indicated they wanted the interactive plot's axes to be logged, log 'em. # But first make sure that values in x and y are loggable! x_axis = False y_axis = False # Checking x axis if np.nanmin(data[name][0][:]) < 0: print('Negative data is incompatible with log plotting.') elif np.nanmin(data[name][0][:]) >= 0 and labels[name][2] == 'log': x_axis = True # Checking y axis if np.nanmin(list(data[name][1][idx])) < 0: print('Negative data is incompatible with log plotting') elif np.nanmin(list( data[name][1][idx])) >= 0 and labels[name][3] == 'log': y_axis = True # Set plot labels plot.setLabel('bottom', '{}'.format(labels[name][0])) plot.setLabel('left', '{}'.format(labels[name][1])) plot.setLogMode(x=x_axis, y=y_axis) # Update x and y range if user modified it tplot_utilities.set_x_range(name, x_axis, plot) tplot_utilities.set_y_range(name, y_axis, plot) # Plot data based on time we're hovering over plot_data.setData(data[name][0][:], list(data[name][1][idx]))
def _visdata(self): self._setcolors() datasets = [pytplot.data_quants[self.tvar_name]] for oplot_name in pytplot.data_quants[ self.tvar_name].attrs['plot_options']['overplots']: datasets.append(pytplot.data_quants[oplot_name]) for dataset in datasets: # Get Linestyle line_style = None if 'linestyle' in pytplot.data_quants[ self.tvar_name].attrs['plot_options']['extras']: line_style = pytplot.data_quants[self.tvar_name].attrs[ 'plot_options']['extras']['linestyle'] # Get a list of formatted times corrected_time = [] for x in dataset.coords['time'].values: corrected_time.append(tplot_utilities.int_to_str(x)) # Bokeh uses milliseconds since epoch for some reason x = dataset.coords['time'].values * 1000.0 # Add region of interest (roi) lines if applicable if 'roi_lines' in pytplot.tplot_opt_glob.keys(): self._set_roi_lines(dataset) plot_options = dataset.attrs['plot_options'] df = pytplot.tplot_utilities.convert_tplotxarray_to_pandas_dataframe( dataset.name) # Create lines from each column in the dataframe for column_name in df.columns: y = df[column_name] # Account for log plotting if self._getyaxistype() == 'log': y.loc[y <= 0] = np.NaN if 'line_style' in plot_options['line_opt']: if plot_options['line_opt']['line_style'] == 'scatter': Glyph = X else: Glyph = Line else: Glyph = Line # Until what size of a data gap are we removing nan values from the dataset? Set by the user # (default is to plot as bokeh would normally plot w/o worrying about data gap handling). limit = pytplot.tplot_opt_glob['data_gap'] if limit != 0: # Grabbing the times associated with nan values (nan_values), and the associated "position" of those # keys in the dataset list (nan_keys) nan_values = y[y.isnull().values].index.tolist() nan_keys = [y.index.tolist().index(j) for j in nan_values] nans = dict(zip(nan_keys, nan_values)) count = 0 # Keeping a count of how big of a time gap we have consec_list = list( ) # List of consecutive nan values (composed of indices for gaps not bigger than # the user-specified data gap) for val in range(len(nan_keys)): # Avoiding some weird issues with going to the last data point in the nan dictionary keys if val != (len(nan_keys) - 1): # Difference between one index and another - if consecutive indices, the diff will be 1 diff = abs(nan_keys[val] - nan_keys[val + 1]) # calculate time accumulated from one index to the next t_now = nan_values[val] t_next = nan_values[val + 1] time_accum = abs(t_now - t_next) # If we haven't reached the allowed data gap, just keep track of how big of a gap we're at, # and the indices in the gap if diff == 1 and count < limit: count += time_accum consec_list.append(nan_keys[val]) # This triggers when we initially exceed the allowed data gap elif diff == 1 and count >= limit: pass # When we find that the previous index and the current one are not consecutive, stop adding to # the consec_list/overall_list (if applicable), and start over the count of time accumulated # in a gap, as well as the consecutive list of time values with nans elif diff != 1: # Restart the count and add the current val to the list of nan values to remove count = 0 consec_list.append(nan_keys[val]) times = x.tolist() for elem in consec_list: # Unless the data gap was big enough, we need to remove nan values from the data, # otherwise bokeh will automatically NOT interpolate (the exact opposite of behavior in # pyqtgraph, which ALWAYS interpolates...). times.remove(nans[elem] * 1000.0) del y[nans[elem]] del corrected_time[corrected_time.index( tplot_utilities.int_to_str(nans[elem]))] # Data to be plotted line_source = ColumnDataSource( data=dict(x=times, y=y, corrected_time=corrected_time)) else: # Data to be plotted line_source = ColumnDataSource( data=dict(x=x, y=y, corrected_time=corrected_time)) if self.auto_color: line = Glyph(x='x', y='y', line_color=self.colors[self.linenum % len(self.colors)]) else: line = Glyph(x='x', y='y') if Glyph == Line: if 'line_style' not in plot_options['line_opt']: if line_style is not None: line.line_dash = line_style[self.linenum % len(line_style)] else: line.line_dash = plot_options['line_style'] self.lineglyphs.append(self.fig.add_glyph(line_source, line)) self.linenum += 1