def add_to_plot(self, fig: go.Figure, bars: List[Bar], time): super().add_to_plot(fig, bars, time) lines = self.channel.get_number_of_lines() styles = self.channel.get_line_styles() names = self.channel.get_line_names() offset = 1 # we take it with offset 1 self.logger.info("adding channel") for idx in range(0, lines): sub_data = list(map(lambda b: self.channel.get_data_for_plot(b)[idx], bars)) fig.add_scatter(x=time, y=sub_data[offset:], mode='lines', line=styles[idx], name=self.channel.id + "_" + names[idx])
def add_to_plot(self, fig: go.Figure, bars: List[Bar], time): super().add_to_plot(fig, bars, time) styles = self.mean.get_line_styles() names = self.mean.get_line_names() offset = 0 # we take it with offset 1 sub_data = list(map(lambda b: self.mean.get_data_for_plot(b)[0], bars)) fig.add_scatter(x=time, y=sub_data[offset:], mode='lines', line=styles[0], name=self.mean.id + "_" + names[0]) sub_data = list(map(lambda b: self.mean.get_data_for_plot(b)[1], bars)) fig.add_scatter(x=time, y=sub_data[offset:], mode='lines', line=styles[1], name=self.mean.id + "_" + names[1]) sub_data = list(map(lambda b: self.mean.get_data_for_plot(b)[2], bars)) fig.add_scatter(x=time, y=sub_data[offset:], mode='lines', line=styles[2], name=self.mean.id + "_" + names[2])
def timeseries_comparison_plot( series_1: pd.Series, series_2: pd.Series, traces_opts: dict = {}, layout_opts: dict = { "xaxis_title": "Time", "yaxis_title": "Values", "autosize": True, "height": 200, }, line_opts: dict = {}, ) -> Figure: """Create a single time series line plot Plotly figure Returns the plotly figure object. """ fig = Figure() # Only thing I figured is - I could do this s1 = series_1.sort_index() fig.add_scatter( x=s1.index, y=s1, mode="lines", name=s1.name if s1.name else "series_1" ) # Not what is desired - need a line s2 = series_2.sort_index() fig.add_scatter( x=s2.index, y=s2, mode="lines", name=s2.name if s2.name else "series_2" ) # Not what is desired - need a line fig.update_layout(**layout_opts) # see https://plotly.com/python/figure-labels/ fig.update_traces(traces_opts) # set line color? fig.update_layout(margin=dict(l=0, r=0, b=0, t=5, pad=0)) fig.update_yaxes(automargin=True) fig.update_xaxes(automargin=True) return fig
def multi_plotly_timeseries_plot( dataframe: pd.DataFrame, traces_opts: dict = {}, layout_opts: dict = { "xaxis_title": "Time", "yaxis_title": "Values", "autosize": True, "height": 200, }, line_opts: dict = {}, ) -> Figure: """Create a single time series line plot Plotly figure Returns the plotly figure object. """ fig = Figure() columns = list(dataframe.keys()) to_plot_df = dataframe.sort_index() # Only thing I figured is - I could do this for key in columns: fig.add_scatter(x=to_plot_df.index, y=to_plot_df[key], mode="lines", name=key) # Not what is desired - need a line fig.update_layout( **layout_opts) # see https://plotly.com/python/figure-labels/ fig.update_traces(traces_opts) # set line color? fig.update_layout(margin=dict(l=0, r=0, b=0, t=5, pad=0)) fig.update_yaxes(automargin=True) fig.update_xaxes(automargin=True) return fig
def substituted_data_plot( raw_values: pd.Series, substitutions: pd.Series, message_series: pd.Series = None, traces_opts: dict = {}, layout_opts: dict = { "xaxis_title": "Time", "yaxis_title": "Values", "autosize": True, "height": 200, }, line_opts: dict = {}, ) -> Figure: """Create a single time series line plot Plotly figure Returns the plotly figure object. """ fig = Figure() s1 = raw_values.sort_index() s1 = s1.loc[~s1.index.duplicated(keep="first")] s2 = substitutions.sort_index() s2 = s2.loc[~s2.index.duplicated(keep="first")] completely_handled_series, replaced_originals, replacements, new_values, deleted = handle_substitutions( s1, s2) fig.add_scatter( x=completely_handled_series.index, y=completely_handled_series, mode="markers+lines", name=raw_values.name + "_substituted" if raw_values.name else "raw_values_substituted", line_color="blue", opacity=0.6, ) # Not what is desired - need a line fig.add_scatter( x=replaced_originals.index, y=replaced_originals, mode="markers", name="replaced raw values", line_color="orange", marker=dict(size=10, opacity=0.6), ) # Not what is desired - need a line fig.add_scatter( x=deleted.index, y=deleted, mode="markers", name="ignored raw values", line_color="red", marker=dict(symbol="x", size=10, opacity=0.6), ) # Not what is desired - need a line fig.add_scatter( x=new_values.index, y=new_values, mode="markers", name="added values", line_color="green", marker=dict(symbol="cross", size=10, opacity=0.6), ) # Not what is desired - need a line fig.update_layout( **layout_opts) # see https://plotly.com/python/figure-labels/ fig.update_traces(traces_opts) # set line color? fig.update_layout(margin=dict(l=0, r=0, b=0, t=5, pad=0)) fig.update_yaxes(automargin=True) fig.update_xaxes(automargin=True) return fig
def _plot(data: SampledField, fig: graph_objects.Figure, size: tuple, colormap: str or None, show_color_bar: bool, row: int = None, col: int = None, ): subplot = fig.get_subplot(row, col) vector = data.points.shape['vector'] if data.spatial_rank == 1 and isinstance(data, Grid): x = data.points.vector[0].numpy().flatten() channels = data.values.shape.channel if channels.rank == 1 and channels.get_item_names(0) is not None: for i, name in enumerate(channels.get_item_names(0)): y = math.reshaped_native(real_values(data[{channels.name: i}]), [data.shape.spatial], to_numpy=True) fig.add_trace(graph_objects.Scatter(x=x, y=y, mode='lines+markers', name=name), row=row, col=col) fig.update_layout(showlegend=True) else: for ch_idx in channels.meshgrid(): y = math.reshaped_native(real_values(data[ch_idx]), [data.shape.spatial], to_numpy=True) fig.add_trace(graph_objects.Scatter(x=x, y=y, mode='lines+markers', name='Multi-channel'), row=row, col=col) fig.update_layout(showlegend=False) elif data.spatial_rank == 2 and isinstance(data, Grid) and 'vector' not in data.shape: # heatmap dims = spatial(data) values = real_values(data).numpy(dims.reversed) x = data.points.vector[dims[0].name].dimension(dims[1].name)[0].numpy() y = data.points.vector[dims[1].name].dimension(dims[0].name)[0].numpy() min_val, max_val = numpy.nanmin(values), numpy.nanmax(values) min_val, max_val = min_val if numpy.isfinite(min_val) else 0, max_val if numpy.isfinite(max_val) else 0 color_scale = get_div_map(min_val, max_val, equal_scale=True, colormap=colormap) # color_bar = graph_objects.heatmap.ColorBar(x=1.15) , colorbar=color_bar fig.add_heatmap(row=row, col=col, x=x, y=y, z=values, zauto=False, zmin=min_val, zmax=max_val, colorscale=color_scale, showscale=show_color_bar) subplot.xaxis.update(scaleanchor=f'y{subplot.yaxis.plotly_name[5:]}', scaleratio=1, constrain='domain', title=dims.names[0]) subplot.yaxis.update(constrain='domain', title=dims.names[1]) elif data.spatial_rank == 2 and isinstance(data, Grid): # vector field if isinstance(data, StaggeredGrid): data = data.at_centers() x, y = math.reshaped_native(data.points.vector[spatial(data)], [vector, data.shape.without(vector)], to_numpy=True, force_expand=True) extra_channels = data.shape.channel.without('vector') data_x, data_y = math.reshaped_native(data.values, [vector, extra_channels, spatial(data)], to_numpy=True, force_expand=True) lower_x, lower_y = [float(l) for l in data.bounds.lower.vector.unstack_spatial('x,y')] upper_x, upper_y = [float(u) for u in data.bounds.upper.vector.unstack_spatial('x,y')] x_range = [lower_x, upper_x] y_range = [lower_y, upper_y] for ch in range(data_x.shape[0]): # quiver = figure_factory.create_quiver(x, y, data_x[ch], data_y[ch], scale=1.0) # 7 points per arrow # fig.add_trace(quiver, row=row, col=col) data_y_flat = data_y[ch].flatten() data_x_flat = data_x[ch].flatten() # lines_y = numpy.stack([y, y + data_y_flat, [None] * len(x)], -1).flatten() # 3 points per arrow # lines_x = numpy.stack([x, x + data_x_flat, [None] * len(x)], -1).flatten() lines_y = numpy.stack([y - data_y_flat / 2, y + data_y_flat / 2, [None] * len(x)], -1).flatten() # 3 points per arrow lines_x = numpy.stack([x - data_x_flat / 2, x + data_x_flat / 2, [None] * len(x)], -1).flatten() name = extra_channels.get_item_names(0)[ch] if extra_channels.rank == 1 and extra_channels.get_item_names(0) is not None else None fig.add_scatter(x=lines_x, y=lines_y, mode='lines', row=row, col=col, name=name) if data_x.shape[0] == 1: fig.update_layout(showlegend=False) subplot.xaxis.update(range=x_range) subplot.yaxis.update(range=y_range) subplot.xaxis.update(scaleanchor=f'y{subplot.yaxis.plotly_name[5:]}', scaleratio=1, constrain='domain') subplot.yaxis.update(constrain='domain') elif data.spatial_rank == 3 and isinstance(data, Grid) and data.shape.channel.volume == 1: # 3D heatmap values = real_values(data).numpy('z,y,x') x = data.points.vector['x'].numpy('z,y,x') y = data.points.vector['y'].numpy('z,y,x') z = data.points.vector['z'].numpy('z,y,x') min_val, max_val = numpy.nanmin(values), numpy.nanmax(values) min_val, max_val = min_val if numpy.isfinite(min_val) else 0, max_val if numpy.isfinite(max_val) else 0 color_scale = get_div_map(min_val, max_val, equal_scale=True, colormap=colormap) fig.add_volume(x=x.flatten(), y=y.flatten(), z=z.flatten(), value=values.flatten(), showscale=show_color_bar, colorscale=color_scale, cmin=min_val, cmax=max_val, cauto=False, isomin=0.1, isomax=0.8, opacity=0.1, # needs to be small to see through all surfaces surface_count=17, # needs to be a large number for good volume rendering row=row, col=col) fig.update_layout(uirevision=True) elif data.spatial_rank == 3 and isinstance(data, Grid): # 3D vector field if isinstance(data, StaggeredGrid): data = data.at_centers() u = real_values(data).vector['x'].numpy('z,y,x') v = real_values(data).vector['y'].numpy('z,y,x') w = real_values(data).vector['z'].numpy('z,y,x') x = data.points.vector['x'].numpy('z,y,x') y = data.points.vector['y'].numpy('z,y,x') z = data.points.vector['z'].numpy('z,y,x') fig.add_cone(x=x.flatten(), y=y.flatten(), z=z.flatten(), u=u.flatten(), v=v.flatten(), w=w.flatten(), colorscale='Blues', sizemode="absolute", sizeref=1, row=row, col=col) elif isinstance(data, PointCloud) and data.spatial_rank == 2 and 'vector' in channel(data): x, y = math.reshaped_native(data.points, [vector, data.shape.without('vector')], to_numpy=True, force_expand=True) u, v = math.reshaped_native(data.values, [vector, data.shape.without('vector')], to_numpy=True, force_expand=True) lower_x, lower_y = [float(d) for d in data.bounds.lower.vector] upper_x, upper_y = [float(d) for d in data.bounds.upper.vector] subplot.xaxis.update(range=[lower_x, upper_x]) subplot.yaxis.update(range=[lower_y, upper_y]) quiver = figure_factory.create_quiver(x, y, u, v, scale=1.0).data[0] # 7 points per arrow if data.color.shape: # color = data.color.numpy(data.shape.non_channel).reshape(-1) warnings.warn("Multi-colored vector plots not yet supported") else: color = data.color.native() quiver.line.update(color=color) fig.add_trace(quiver, row=row, col=col) if data.points.vector.item_names: subplot.xaxis.update(title=data.points.vector.item_names[0]) subplot.yaxis.update(title=data.points.vector.item_names[1]) subplot.xaxis.update(scaleanchor=f'y{subplot.yaxis.plotly_name[5:]}', scaleratio=1, constrain='domain') subplot.yaxis.update(constrain='domain') elif isinstance(data, PointCloud) and data.spatial_rank == 2: lower_x, lower_y = [float(d) for d in data.bounds.lower.vector] upper_x, upper_y = [float(d) for d in data.bounds.upper.vector] if data.points.shape.non_channel.rank > 1: data_list = field.unstack(data, data.points.shape.non_channel[0].name) for d in data_list: _plot(d, fig, size, colormap, show_color_bar, row, col) else: x, y = [d.numpy() for d in data.points.vector.unstack_spatial('x,y')] color = data.color.native() subplot_height = (subplot.yaxis.domain[1] - subplot.yaxis.domain[0]) * size[1] if isinstance(data.elements, Sphere): symbol = 'circle' marker_size = data.elements.bounding_radius().numpy() * 1.9 elif isinstance(data.elements, BaseBox): symbol = 'square' marker_size = math.mean(data.elements.bounding_half_extent(), 'vector').numpy() * 1 elif isinstance(data.elements, Point): symbol = 'x' marker_size = 12 / (subplot_height / (upper_y - lower_y)) else: symbol = 'asterisk' marker_size = data.elements.bounding_radius().numpy() marker_size *= subplot_height / (upper_y - lower_y) marker = graph_objects.scatter.Marker(size=marker_size, color=color, sizemode='diameter', symbol=symbol) fig.add_scatter(mode='markers', x=x, y=y, marker=marker, row=row, col=col) subplot.xaxis.update(range=[lower_x, upper_x]) subplot.yaxis.update(range=[lower_y, upper_y]) fig.update_layout(showlegend=False) subplot.xaxis.update(scaleanchor=f'y{subplot.yaxis.plotly_name[5:]}', scaleratio=1, constrain='domain') subplot.yaxis.update(constrain='domain') elif isinstance(data, PointCloud) and data.spatial_rank == 3: lower_x, lower_y, lower_z = [float(d) for d in data.bounds.lower.vector.unstack_spatial('x,y,z')] upper_x, upper_y, upper_z = [float(d) for d in data.bounds.upper.vector.unstack_spatial('x,y,z')] if data.points.shape.non_channel.rank > 1: data_list = field.unstack(data, data.points.shape.non_channel[0].name) for d in data_list: _plot(d, fig, size, colormap, show_color_bar, row, col) else: x, y, z = [d.numpy() for d in data.points.vector.unstack_spatial('x,y,z')] color = data.color.native() # if data.color.shape.instance_rank == 0: # color = str(data.color) # else: # color = [str(d) for d in math.unstack(data.color, instance)] domain_y = fig.layout[subplot.plotly_name].domain.y if isinstance(data.elements, Sphere): symbol = 'circle' marker_size = data.elements.bounding_radius().numpy() * 2 elif isinstance(data.elements, BaseBox): symbol = 'square' marker_size = math.mean(data.elements.bounding_half_extent(), 'vector').numpy() * 1 elif isinstance(data.elements, Point): symbol = 'x' marker_size = 4 / (size[1] * (domain_y[1] - domain_y[0]) / (upper_y - lower_y) * 0.5) else: symbol = 'asterisk' marker_size = data.elements.bounding_radius().numpy() marker_size *= size[1] * (domain_y[1] - domain_y[0]) / (upper_y - lower_y) * 0.5 marker = graph_objects.scatter3d.Marker(size=marker_size, color=color, sizemode='diameter', symbol=symbol) fig.add_scatter3d(mode='markers', x=x, y=y, z=z, marker=marker, row=row, col=col) subplot.xaxis.update(range=[lower_x, upper_x]) subplot.yaxis.update(range=[lower_y, upper_y]) subplot.zaxis.update(range=[lower_z, upper_z]) fig.update_layout(showlegend=False) else: raise NotImplementedError(f"No figure recipe for {data}")
def timeseries_comparison_plot( series_1: pd.Series, series_2: pd.Series, limit_violation_timestamp: str, limit: float, traces_opts: dict = {}, layout_opts: dict = { "xaxis_title": "Time", "yaxis_title": "Values", "autosize": True, "height": 200, }, line_opts: dict = {}, ) -> Figure: """Create a single time series line plot Plotly figure Returns the plotly figure object. """ fig = Figure() # Only thing I figured is - I could do this s1 = series_1.sort_index() fig.add_scatter( x=s1.index, y=s1, mode="lines", name=s1.name if s1.name else "series_1" ) # Not what is desired - need a line s2 = series_2.sort_index() fig.add_scatter( x=s2.index, y=s2, mode="lines", name=s2.name if s2.name else "series_2" ) # Not what is desired - need a line fig.update_layout(**layout_opts) # see https://plotly.com/python/figure-labels/ fig.update_traces(traces_opts) # set line color? vline_y_min = np.min([series_1.min(), series_2.min(), limit]) vline_y_max = np.max([series_1.max(), series_2.max(), limit]) hline_x_min = np.min([series_1.index.min(), series_2.index.min()]) hline_x_max = np.max([series_1.index.max(), series_2.index.max()]) fig.update_layout( shapes=( [ dict( type="line", yref="y", y0=vline_y_min, y1=vline_y_max, xref="x", x0=limit_violation_timestamp, x1=limit_violation_timestamp, ) ] if limit_violation_timestamp is not None else [] ) + [ dict( type="line", yref="y", y0=limit, y1=limit, xref="x", x0=hline_x_min, x1=hline_x_max, line={"color": "red", "width": 1}, ) ] ) fig.update_layout(margin=dict(l=0, r=0, b=0, t=5, pad=0)) fig.update_yaxes(automargin=True) fig.update_xaxes(automargin=True) return fig
def timeseries_comparison_plot( series_1: pd.Series, series_2: pd.Series, freq, freq_factor, max_shifts_past, max_shifts_future, traces_opts: dict = {}, layout_opts: dict = { "xaxis_title": "Time", "yaxis_title": "Values", "autosize": True, "height": 480, }, line_opts: dict = {}, ) -> Figure: """Create a single time series line plot Plotly figure Returns the plotly figure object. """ if max_shifts_past < 0 or max_shifts_future < 0: raise ValueError("Shift maxima values must be greater equal zero.") fig = Figure() s1 = series_1.sort_index() fig.add_scatter( x=s1.index, y=s1, mode="lines", name=s1.name if (s1.name and s1.name != "measurement") else "series", ) s2 = series_2.sort_index() for step in np.arange(-max_shifts_past, max_shifts_future, 1): shifted = s2.copy() shifted.index = shifted.index.shift(periods=step * freq_factor, freq=freq) fig.add_scatter( x=shifted.index, y=shifted, mode="lines", name=shifted.name if (shifted.name and shifted.name != "measurement") else "series_shiftable", visible=False, ) fig.data[max_shifts_past + 1].visible = True # start somewhere steps = [] for i in range(len(fig.data)): step = dict( method="update", args=[ { "visible": [False] * (len(fig.data)) }, { "title": f"Shifted by x times frequency {freq_factor}{freq}: " + str(i - max_shifts_past - 1) }, ], # layout attribute ) step["args"][0]["visible"][i] = True # Toggle i'th trace to "visible" step["args"][0]["visible"][0] = True step["label"] = str(i - max_shifts_past - 1) steps.append(step) sliders = [ dict( active=max_shifts_past, currentvalue={ "prefix": f"Shifted by x times frequency {freq_factor}{freq}: " }, pad={ "t": 80, "b": 10 }, steps=steps[1:], ) ] fig.update_layout( **layout_opts) # see https://plotly.com/python/figure-labels/ fig.update_traces(traces_opts) # set line color? fig.update_layout(margin=dict(l=0, r=0, b=40, t=30, pad=10)) fig.update_yaxes(automargin=True) fig.update_xaxes(automargin=True) fig.update_layout(sliders=sliders) return fig