def _plotly_vector_plot2(x, y, Field, NQ, scale_x, scale_y, vector_color): """Draws quiver plot of field vectors Args: x (float/array): x coordinates y (float/array): y coordinates Field (Vector2): Field structure NQ (int): Plot every NQth vector scale_x (float): unit scaling scale_y (float): unit scaling vector_color (string): quiver color """ plot_object = [] NPx, NPy = x.shape if NQ != 0: NSx, NSy = NPx // NQ, NPy // NQ with _np.errstate(divide="ignore", invalid="ignore"): plot_object = _ff.create_quiver( x[::NSx, ::NSy] / scale_x, y[::NSx, ::NSy] / scale_y, Field.x[::NSx, ::NSy] / Field.n[::NSx, ::NSy], Field.y[::NSx, ::NSy] / Field.n[::NSx, ::NSy], scale=1.5, arrow_scale=0.5, # name='quiver', line_width=1, line=dict(color="white"), ) return plot_object
def trace_vector(vect, option='origin', scalvect=1, titre="sans titre"): if isinstance(vect, Vector): vect = [vect] uxL = [v[0] for v in vect] uyL = [v[1] for v in vect] xL = [0] * len(vect) yL = [0] * len(vect) if option == 'a_la_suite': for i, v in enumerate(vect): if i != 0: xL[i] = scalvect * uxL[i - 1] + xL[i - 1] yL[i] = scalvect * uyL[i - 1] + yL[i - 1] quiver_fig = ff.create_quiver( xL, yL, uxL, uyL, scale=scalvect, arrow_scale=.05, # Sets arrow scale name='vecteur', angle=np.pi / 12, line=dict(width=3)) for x, y, v in zip(xL, yL, vect): data = go.Scatter(x=np.array(x), y=np.array(y), mode='markers', marker=dict(size=8, color='grey'), name=f'{v.name} norme={v.norm():.2f} N') quiver_fig.add_trace(data) layout = go.Layout(title=titre, xaxis=dict(constrain='domain', title='x'), yaxis=dict(scaleanchor='x', title='y')) quiver_fig['layout'].update(layout) return iplot(quiver_fig, filename='vecteur')
def draw_vector_field(self, vector_field, library): x, y = numpy.meshgrid(numpy.arange(0, vector_field.shape[1], 1), numpy.arange(0, vector_field.shape[0], 1)) if library == 'dash': if self.draw_arrows_backward: return ff.create_quiver(x - vector_field[..., 0], y - vector_field[..., 1], vector_field[..., 0], vector_field[..., 1], scale=1.0) else: return ff.create_quiver(x, y, vector_field[..., 0], vector_field[..., 1], scale=1.0) else: raise NotImplementedError()
def ShowVectors(gV): plotly.tools.set_credentials_file(username='******', api_key='AHpO2zYe4pzOOddMe4nz') init_notebook_mode(connected=True) # Getting data points ''' sX = [] sY = [] sC = [] rX = [] rY = [] rC = [] for i in range( len(hV) ): if hCol[i] == 'red' : sX.append( hV[i][0] ) sY.append( hV[i][1] ) sC.append( 'red' ) else : rX.append( hV[i][0] ) rY.append( hV[i][1] ) rC.append( 'black' ) ''' # Adding vectors X = 0 Y = 0 j = 0 vX = [] vY = [] U = [] V = [] for i in gV: dX = i[0] - X dY = i[1] - Y vX.append(X) vY.append(Y) U.append(dX) V.append(dY) #print(" i= " + str(i) + "( " + str( i[0]) + ", " + str(i[1]) + ")" ) #plt.quiver( X, Y, dX, dY, angles='xy', scale_units='xy',scale=1, color= colorV[j] ) X += dX Y += dY j += 1 fig = ff.create_quiver(vX, vY, U, V) # adding retract points #aplt.scatter( sX, sY,s=20, c=sC, marker= '^') #plt.scatter( rX, rY,s=20, c=rC, marker= 'o') plt.iplot(fig)
def quiver(self, factor=1): xg, yg = self.xpixels.pixel_grids xg = 0.5 * (xg[1:] + xg[:-1]) yg = 0.5 * (yg[1:] + yg[:-1]) x, y = np.meshgrid(xg, yg) fig = ff.create_quiver( x, y, self.xpixels.pixels.T, self.ypixels.pixels.T, scale=factor, ) return fig
def vector_plot(result, titles, verbose=False, **kwargs): variable = titles['variable'] val0 = list(result.values())[0] if (result[variable].shape == val0.shape) & (val0.shape[1] == 2): if verbose: print('\t 2-d output', result[variable].shape) u = result[variable][:, 0] v = result[variable][:, 1] x = val0[:, 0] y = val0[:, 1] trace = ff.create_quiver( x, y, u, v, # scale=.25, # arrow_scale=.4, name='quiver', line=dict(width=1))['data'][0] # extracts quiver trace layout = go.Layout(title=titles['title'], xaxis=dict(title='x'), yaxis=dict(title='y')) chart_type = '2d-vector' elif (result[variable].shape == val0.shape) & (val0.shape[1] == 3): if verbose: print('\t 3-d output', result[variable].shape) u = result[variable][:, 0].tolist() v = result[variable][:, 1].tolist() w = result[variable][:, 2].tolist() x = val0[:, 0].tolist() y = val0[:, 1].tolist() z = val0[:, 2].tolist() trace = go.Cone(x=x, y=y, z=z, u=u, v=v, w=w) layout = go.Layout(title=titles['title'], scene=dict( xaxis=dict(title='x'), yaxis=dict(title='y'), zaxis=dict(title='z'), )) chart_type = '3d-vector' else: raise NotImplementedError('plot type not supported yet') return [trace], chart_type, layout
def iplot( self, scale: float = 1., height: int = 1000, width: int = 1000, ) -> plotly.graph_objs._figure.Figure: pointing = self.azimuthal_equidistant_projection_with_orientation temp = pointing[:, :2] * (180. / np.pi) x = temp[:, 0] y = temp[:, 1] u = np.cos(pointing[:, 2]) v = np.sin(pointing[:, 2]) fig = ff.create_quiver(x, y, u, v, scale=scale, scaleratio=1.) fig.update_layout(height=height, width=width) return fig
def plot_2D(func, plane='xy', limits=[(-20e-3, 20e-3), (-20e-3, 20e-3)], numpoints=40, quiver=True, quiver_scale=5e-4, component='all'): ''' Generates a 2D plot of the passed vector function in the given plane. ''' i = ord(plane[0]) - 120 # ordinate index j = ord(plane[1]) - 120 # abscissa index X, agrid, a = sample_2d(func, plane, limits, numpoints, component=component) xi = np.unique(X[:, i]) xj = np.unique(X[:, j]) ## create heatmap for norm of function fig = go.Figure() surf = go.Heatmap(x=xi, y=xj, z=agrid, colorscale="Rainbow", zsmooth='best', colorbar={ 'title': 'Acceleration', 'titleside': 'right' }) if quiver: n = numpoints X2, agrid2, a2 = X, agrid, a ## create quiver plot xg = X2[:, i].reshape(n, n) yg = X2[:, j].reshape(n, n) ax = (a2[:, i] / np.linalg.norm(a2, axis=1)).reshape(n, n) ay = (a2[:, j] / np.linalg.norm(a2, axis=1)).reshape(n, n) fig = ff.create_quiver(xg, yg, ax, ay, scale=quiver_scale) fig['data'][0]['line']['color'] = 'rgb(255,255,255)' fig.add_trace(surf) fig.update_xaxes(range=[xi.min(), xi.max()]) fig.update_yaxes(range=[xj.min(), xj.max()]) return fig
def plot_2d_quiver(omega, theta): # skew_matrix = skew2d(omega) skew_matrix = np.array([[0, -omega], [omega, 0]]) x,y = np.meshgrid(np.arange(-2, 2, .5), np.arange(-2, 2, .5)) u = skew_matrix[0][0] * x + skew_matrix[0][1] * y v = skew_matrix[1][0] * x + skew_matrix[1][1] * y # Create quiver figure fig = ff.create_quiver(x, y, u, v, scale=.25, arrow_scale=.4, name='quiver', line_width=1) # Add points to figure fig.add_trace(go.Scatter(x=[0.], y=[0.], mode='markers', marker_size=12, name='points')) x0 = 1.0 y0 = 0.6 x_traj = [x0] y_traj = [y0] dt = 0.05 t = 0 while t < theta: t += dt dx = skew_matrix[0][0] * x_traj[-1] + skew_matrix[0][1] * y_traj[-1] dy = skew_matrix[1][0] * x_traj[-1] + skew_matrix[1][1] * y_traj[-1] x_traj.append(x_traj[-1] + dx * dt) y_traj.append(y_traj[-1] + dy * dt) if theta > 0: fig.add_trace(go.Scatter(x=x_traj, y=y_traj, mode="lines", line=dict(color='firebrick', width=4))) # Add calculation return fig
def showsolution(node,elem,u,**kwargs): ''' show 2D solution either of a scalar function or a vector field ''' markersize = 3000/len(node) if u.ndim == 1: uplot = ff.create_trisurf(x=node[:,0], y=node[:,1], z=u, simplices=elem, colormap="Viridis", # similar to matlab's default colormap showbackground=False, aspectratio=dict(x=1, y=1, z=1), ) fig = go.Figure(data=uplot) elif u.ndim == 2 and u.shape[-1] == 2: assert u.shape[0] == elem.shape[0] u /= (np.abs(u)).max() center = node[elem].mean(axis=1) uplot = ff.create_quiver(x=center[:,0], y=center[:,1], u=u[:,0], v=u[:,1], scale=.05, arrow_scale=.5, name='gradient of u', line_width=1, ) # uplot.add_trace(go.Scatter(x=center[:,0], y=center[:,1], # mode='markers', # marker=dict( # color='LightSkyBlue', # size=markersize, # # line=dict( # # color='MediumPurple', # # width=12 # # ) # ), # name='nodes in mesh')) fig = go.Figure(data=uplot) fig.update_layout(template='plotly_dark', margin=dict(l=5, r=5, t=5, b=5), **kwargs) fig.show()
def velocities(tracking_data): velocity_quivers = [] for i, side in enumerate(['Home', 'Away']): team_data = tracking_data[i] player_nums = list(set(item for subitem in team_data.keys() for item in subitem.split('_') if item.isdigit())) xlocs = [team_data['{}_{}_{}'.format( side, num, 'x')] for num in player_nums] ylocs = [team_data['{}_{}_{}'.format( side, num, 'y')] for num in player_nums] xvels = [team_data['{}_{}_{}'.format( side, num, 'vx')] for num in player_nums] yvels = [team_data['{}_{}_{}'.format( side, num, 'vy')] for num in player_nums] trace = ff.create_quiver(x=xlocs, y=ylocs, u=xvels, v=yvels, scale=.5, line_color=player_marker_args[side]['marker_color'], name=side+'_vel') velocity_quivers.append(trace.data[0]) return velocity_quivers
def plot_gradient(self, func, bounds=[-5, 5], seperate_window=False): '''Quiver plot to the visualize the gradient. ''' f_x = func.diff(self.x) f_y = func.diff(self.y) fx = lambdify([self.x, self.y], f_x, 'numpy') fy = lambdify([self.x, self.y], f_y, 'numpy') # Define numerical space x_range = np.arange(bounds[0], bounds[1], 1) y_range = np.arange(bounds[0], bounds[1], 1) x_, y_ = np.meshgrid(x_range, y_range) u = fx(x_, y_) v = fy(x_, y_) fig = ff.create_quiver(x_, y_, u, v) # Show if seperate_window: plot(fig, show_link=False) else: iplot(fig, show_link=False)
def velocity_traces(self, frame_data): player_ids = (self.home_players, self.away_players) velocity_quivers = [] for i, side in enumerate(["Home", "Away"]): players = player_ids[i] xlocs = [frame_data[f"{player_id}_x"] for player_id in players] ylocs = [frame_data[f"{player_id}_y"] for player_id in players] xvels = [frame_data[f"{player_id}_vx"] for player_id in players] yvels = [frame_data[f"{player_id}_vy"] for player_id in players] trace = ff.create_quiver( x=xlocs, y=ylocs, u=xvels, v=yvels, scale=0.5, line_color=prm.player_marker_args[side]["marker_color"], name=side + "_vel", ) velocity_quivers.append(trace.data[0]) return velocity_quivers
def plot_quiver(): x, y = np.meshgrid(np.arange(-2, 2, .2), np.arange(-2, 2, .25)) z = x * np.exp(-x**2 - y**2) v, u = np.gradient(z, .2, .2) # Create quiver figure fig = ff.create_quiver(x, y, u, v, scale=.25, arrow_scale=.4, name='quiver', line_width=1) # Add points to figure fig.add_trace( go.Scatter(x=[-.7, .75], y=[0, 0], mode='markers', marker_size=12, name='points')) return fig
def velocity_traces(self, frame_data): velocity_quivers = [] for i, side in enumerate(["Home", "Away"]): team_data = frame_data[i] player_nums = list( set(item for subitem in team_data.keys() for item in subitem.split("_") if item.isdigit())) xlocs = [ team_data["{}_{}_{}".format(side, num, "X")] for num in player_nums ] ylocs = [ team_data["{}_{}_{}".format(side, num, "Y")] for num in player_nums ] xvels = [ team_data["{}_{}_{}".format(side, num, "vx")] for num in player_nums ] yvels = [ team_data["{}_{}_{}".format(side, num, "vy")] for num in player_nums ] trace = ff.create_quiver( x=xlocs, y=ylocs, u=xvels, v=yvels, scale=0.5, line_color=prm.player_marker_args[side]["marker_color"], name=side + "_vel", ) velocity_quivers.append(trace.data[0]) return velocity_quivers
def draw_wires(fig, toDraw, TimeStamp=0, PathInd=[]): wires_toDraw = [] sectionCenterX = np.array([]) sectionCenterY = np.array([]) sectionCurrentX = np.array([]) sectionCurrentY = np.array([]) for this_wire in toDraw.Nanowires: if not this_wire in wires_toDraw: wires_toDraw.append(this_wire) sectionCenterX = np.append(sectionCenterX, this_wire.sectionCenterX) sectionCenterY = np.append(sectionCenterY, this_wire.sectionCenterY) sectionCurrentX = np.append( sectionCurrentX, this_wire.sectionCurrentX[TimeStamp, :]) sectionCurrentY = np.append( sectionCurrentY, this_wire.sectionCurrentY[TimeStamp, :]) for this_wire in wires_toDraw: xa, ya, xb, yb = this_wire.wireEnds xc, yc = this_wire.centerPosition this_opacity = 0.2 + 0.8 * (this_wire.onPathChecker[TimeStamp] != 0) if this_wire.index in PathInd: this_color = 'yellow' else: this_color = 'white' line = go.Scatter(x=[xa, xb, xc], y=[ya, yb, yc], name='Nanowire #' + str(this_wire.index), mode="lines", hoverinfo='name', opacity=this_opacity, line=dict(color=this_color, width=1.5)) fig.add_trace(line) if this_wire.isElectrode != 0: if this_wire.isElectrode == 1: electrodeColor = 'green' type = 'source' else: electrodeColor = 'red' type = 'drain' temp = go.Scatter(x=[this_wire.contactEnd[0]], y=[this_wire.contactEnd[1]], mode='markers', name=type, opacity=0.9, marker=dict(symbol='hexagon', color=electrodeColor, size=30), hoverinfo='name') fig.add_trace(temp) quivers = ff.create_quiver(sectionCenterX, sectionCenterY, 1e8 * sectionCurrentX, 1e8 * sectionCurrentY, scale=0.1, arrow_scale=0.3, name='Current', opacity=0.9, hoverinfo='none', line=dict(color='red', width=3)) fig.add_trace(quivers.data[0]) return fig
def create_quiver(*args, **kwargs): FigureFactory._deprecated('create_quiver') from plotly.figure_factory import create_quiver return create_quiver(*args, **kwargs)
def update_2d_sis(beta, gamma, delta, sigma, epsilon, p, S_0, I_0, aux): '''Updates the 3d Plot''' # Test values T = 200 # Handle None Case if S_0 is None: S_0 = 80 if I_0 is None: I_0 = 20 # Data for trajectory t, y = SIS(S_0, I_0, beta, gamma, delta, sigma, epsilon, p, T) # Draw vector field S_max = y[0].max() I_max = y[1].max() grid_max = np.array([S_max, I_max]) xx, uu = eval_on_grid_2d(func=f_sis, x_min=np.zeros_like(grid_max), x_max=grid_max, t=0, n_points=20, beta=beta, gamma=gamma, delta=delta, sigma=sigma, epsilon=epsilon, p=p) fig = ff.create_quiver( x=xx[:, 0], y=xx[:, 1], u=uu[:, 0], v=uu[:, 1], name='Vector Field', scale=.4, ) # Make figure fig.add_traces([ go.Scatter( name='Intial Conditions', x=[S_0], y=[I_0], mode='markers', marker=dict(size=10, opacity=.5), ), go.Scatter( name='Sample Trajectory', x=y[0], y=y[1], mode='lines+markers', marker=dict( color=t, colorscale='Viridis', size=2, ), ), ]) fig.update_layout( title="Trajectories of the SIS Model", xaxis_title='Susceptible', yaxis_title='Infected', margin=dict(l=0, r=0, b=0, t=0), legend=dict( x=0, y=1, bgcolor='rgba(255,255,255,.5)', ), ) return fig
def plot_quiver(self, p_meshgrid_spacing=0.02): # Arrange data. x, y = np.meshgrid( np.arange(self.msh.x0, self.msh.xf, p_meshgrid_spacing), np.arange(self.msh.y0, self.msh.yf, p_meshgrid_spacing)) the_problem = self.usr.get('problem', 'Smith-Hutton') if the_problem == 'Diagonal flow': u = np.ones(x.shape) * self.fields.vx v = np.ones(x.shape) * self.fields.vy the_scale = 0.0025 the_arrow_scale = 0.5 else: # Prepare the mesh and velocity field for the quiver plot function. n_nodes = self.msh.M * self.msh.N # Rearrange the nodes x,y coords in a single array, and flatten the vx,vy velocities. the_points = np.zeros((n_nodes, 2)) u = np.zeros((n_nodes, )) v = np.zeros((n_nodes, )) i = 0 for row in range(self.msh.M): for col in range(self.msh.N): the_points[i, 0] = self.msh.cells_x_coords[row, col] the_points[i, 1] = self.msh.cells_y_coords[row, col] u[i] = self.fields.vx[row, col] v[i] = self.fields.vy[row, col] i = i + 1 x_ = np.linspace(self.msh.x0, self.msh.xf, 50) y_ = np.linspace(self.msh.y0, self.msh.yf, 50) x, y = np.meshgrid(x_, y_) u = griddata(the_points, u, (x, y), method='cubic') v = griddata(the_points, v, (x, y), method='cubic') the_scale = 0.02 the_arrow_scale = 0.3 # Build the figure. fig = ff.create_quiver(x, y, u, v, name='Velocity field', scale=the_scale, arrow_scale=the_arrow_scale) # Plot origin.- fig.add_trace( go.Scatter( x=[0], y=[0], name='Origin', mode='markers' #, # marker_size=15 )) # Figure config. separator = '-' space_m = '\:' problem = self.usr.get('problem', '') if problem == 'Smith-Hutton': problem = 'Smith \: Hutton' title = 'Quiver' + separator + problem title = '$' + title + '$' fig.update_layout(title={ 'text': title, 'x': 0.05, 'xanchor': 'left', 'yanchor': 'top' }, xaxis_title="x (m)", yaxis_title="y (m)", font={'size': 15}) fig.show()
def vector_field(field2d, settings): assert isinstance(field2d, (CenteredGrid, StaggeredGrid)) if isinstance(field2d, StaggeredGrid): field2d = field2d.at_centers() assert isinstance(field2d, CenteredGrid) assert field2d.rank == 2 batch = settings.get('batch', 0) batch = min(batch, field2d.data.shape[0]) arrow_origin = settings.get('arrow_origin', 'tip') assert arrow_origin in ('base', 'center', 'tip') max_resolution = settings.get('max_arrow_resolution', 40) max_arrows = settings.get('max_arrows', 2000) min_arrow_length = settings.get('min_arrow_length', 0.005) * np.max( field2d.box.size) draw_full_arrows = settings.get('draw_full_arrows', False) y, x = field2d.points.data[0, ..., (physics_config.y, physics_config.x)] data_y, data_x = field2d.data[batch, ..., (physics_config.y, physics_config.x)] while np.prod(x.shape) > max_resolution**2: y = y[::2, ::2] x = x[::2, ::2] data_y = data_y[::2, ::2] data_x = data_x[::2, ::2] y = y.flatten() x = x.flatten() data_y = data_y.flatten() data_x = data_x.flatten() if max_arrows is not None or min_arrow_length > 0: length = np.sqrt(data_y**2 + data_x**2) keep_indices = np.argsort(length) keep_indices = keep_indices[length[keep_indices] > min_arrow_length] if len(keep_indices) > max_arrows: keep_indices = keep_indices[-max_arrows:] y = y[keep_indices] x = x[keep_indices] data_y = data_y[keep_indices] data_x = data_x[keep_indices] if len(x) == 0: return EMPTY_FIGURE if arrow_origin == 'tip': x -= data_x y -= data_y elif arrow_origin == 'center': x -= 0.5 * data_x y -= 0.5 * data_y x_range, y_range = [field2d.box.get_lower(1), field2d.box.get_upper(1)], [ field2d.box.get_lower(0), field2d.box.get_upper(0) ] if physics_config.is_x_first: x_range, y_range = y_range, x_range if draw_full_arrows: result = plotly_figures.create_quiver(x, y, data_x, data_y, scale=1.0) # 7 points per arrow result.update_xaxes(range=x_range) result.update_yaxes(range=y_range) return result else: lines_y = np.stack([y, y + data_y, [None] * len(x)], -1).flatten() # 3 points per arrow lines_x = np.stack([x, x + data_x, [None] * len(x)], -1).flatten() return { 'data': [{ 'mode': 'lines', 'x': lines_x, 'y': lines_y, 'type': 'scatter', }], 'layout': { 'xaxis': { 'range': x_range }, 'yaxis': { 'range': y_range }, } }
def vector_field(field2d, settings): assert isinstance(field2d, (CenteredGrid, StaggeredGrid)) if isinstance(field2d, StaggeredGrid): field2d = field2d.at_centers() assert isinstance(field2d, CenteredGrid) assert field2d.rank == 2 batch = settings.get('batch', 0) batch = min(batch, field2d.data.shape[0]) arrow_origin = settings.get('arrow_origin', 'tip') assert arrow_origin in ('base', 'center', 'tip') max_resolution = settings.get('max_arrow_resolution', 40) max_arrows = settings.get('max_arrows', 300) draw_full_arrows = settings.get('draw_full_arrows', False) y, x = math.unstack(field2d.points.data[0, ..., -2:], axis=-1) data_y, data_x = math.unstack(field2d.data[batch, ...], -1)[-2:] while np.prod(x.shape) > max_resolution**2: y = y[::2, ::2] x = x[::2, ::2] data_y = data_y[::2, ::2] data_x = data_x[::2, ::2] y = y.flatten() x = x.flatten() data_y = data_y.flatten() data_x = data_x.flatten() if max_arrows is not None and len(x) > max_arrows: length = np.sqrt(data_y**2 + data_x**2) keep_indices = np.argsort(length)[-max_arrows:] # size = np.max(field2d.box.size) # threshold = size * negligible_threshold # keep_condition = (np.abs(data_x) > threshold) | (np.abs(data_y) > threshold) # keep_indices = np.where(keep_condition) y = y[keep_indices] x = x[keep_indices] data_y = data_y[keep_indices] data_x = data_x[keep_indices] if arrow_origin == 'tip': x -= data_x y -= data_y elif arrow_origin == 'center': x -= 0.5 * data_x y -= 0.5 * data_y if draw_full_arrows: result = plotly_figures.create_quiver(x, y, data_x, data_y, scale=1.0) # 7 points per arrow result.update_xaxes( range=[field2d.box.get_lower(1), field2d.box.get_upper(1)]) result.update_yaxes( range=[field2d.box.get_lower(0), field2d.box.get_upper(0)]) return result else: lines_y = np.stack([y, y + data_y, [None] * len(x)], -1).flatten() # 3 points per arrow lines_x = np.stack([x, x + data_x, [None] * len(x)], -1).flatten() return { 'data': [{ 'mode': 'lines', 'x': lines_x, 'y': lines_y, 'type': 'scatter', }], 'layout': { 'xaxis': { 'range': [field2d.box.get_lower(1), field2d.box.get_upper(1)] }, 'yaxis': { 'range': [field2d.box.get_lower(0), field2d.box.get_upper(0)] }, } }
def plot_2D_quiver(pixels: Union[torch.Tensor, dict], grad_pixels: Union[torch.Tensor, dict], img_mask_gt: torch.Tensor, img_mask_grad=None, img=None, n_debug_points=400, save_html=None) -> go.Figure: """ Plot 2D quiver plots, for each point, point the negative gradient projected on 2D image space. Accept dictionaries of {str: tensor(N,3)} or tensors (N,3). In case dictionaries are proviced, the keys are used for hovertext, otherwise, the indices of points are used. Args: pts_ndc (tensor): (P, 3) or dictionary {name: tensor(P,3)} pts_grad_ndc (tensor): the vector projected to ndc space, i.e. proj(pts+grad) img_mask_gt (tensor): (H,W,1) value from ground truth mask img_mask_grad (tensor): (H,W,1) value from occupancy map gradient img (tensor): (H,W,3) value of the rendered rgb, will be ignored if img_mask_grad is provided n_debug_points (int): plot limited number of quiver to better readability, if < 0, plot all. save_html (str): If given, then save to file """ H, W = img_mask_gt.shape[:2] img_mask_gt = img_mask_gt.cpu() resolution = torch.tensor((W, H), device=img_mask_gt.device, dtype=torch.float) if img_mask_gt.ndim == 3: img_mask_gt.squeeze_(-1) assert (img_mask_gt.ndim == 2) n_pts_per_cat = None text_to_id = None if isinstance(pixels, torch.Tensor): pixels = pixels.cpu() grad_pixels = grad_pixels.cpu() text = np.array([str(i) for i in range(pixels.shape[0])]) n_pts_per_cat = OrderedDict(all=pixels.shape[0]) elif isinstance(pixels, dict): n_pts_per_cat = OrderedDict( (k, pts.shape[0]) for k, pts in pixels.items()) text_to_id = {k: i for i, k in enumerate(pixels)} pixels = torch.cat([pixels[k] for k in n_pts_per_cat.keys()], dim=0) grad_pixels = torch.cat([grad_pixels[k] for k in n_pts_per_cat.keys()], dim=0) pixels = pixels.cpu() grad_pixels = grad_pixels.cpu() text = np.array( [k for k, pts in n_pts_per_cat.items() for i in range(pts)]) assert ( grad_pixels.shape == pixels.shape), 'Found unequal pts and pts_grad.' # convert ndc to pixel # pixels = ndc_to_pix(pixels, resolution).cpu() # grad_pixels = ndc_to_pix(pts_grad_ndc, resolution).cpu() uv = grad_pixels - pixels valid_mask = ((pixels < resolution) & (pixels >= 0)).all(dim=-1) pixels = pixels[valid_mask] grad_pixels = grad_pixels[valid_mask] uv = uv[valid_mask] # scale uv to less than 1/5 image size # based on the gradient magnitude, select top points to visualize if n_debug_points > 0: _, indices = torch.sort(torch.norm(uv, dim=-1), dim=0, descending=True) indices = indices[:n_debug_points].cpu() # plot quiver for gradient pixels_selected = pixels[indices].numpy() grad_pixels_selected = grad_pixels[indices].numpy() text_selected = text[indices.numpy()] uv_selected = uv[indices].numpy() else: # plot quiver for gradient pixels_selected = pixels.numpy() grad_pixels_selected = grad_pixels.numpy() text_selected = text uv_selected = uv.numpy() uv_selected = uv_selected / \ np.linalg.norm(uv_selected, axis=-1).max().item() * max(H, W) * 0.1 fig = ff.create_quiver( x=pixels_selected[:, 0], y=pixels_selected[:, 1], u=-uv_selected[:, 0], v=-uv_selected[:, 1], name=('proj_grad'), hoverinfo='none', marker_color='orange', scale=.25, arrow_scale=.4, ) # draw all points with different colors _start_pts = 0 for k, n_pts in n_pts_per_cat.items(): _pixels = pixels[_start_pts:(n_pts + _start_pts)].cpu().numpy() t0 = time.time() fig.add_traces( go.Scatter(x=_pixels[:, 0], y=_pixels[:, 1], name=k, mode='markers', marker_size=5, hoverinfo='text', text=text[_start_pts:(n_pts + _start_pts)])) t1 = time.time() # print('2D Scatter {} {:.3f}'.format(k, t1-t0)) _start_pts += n_pts fig.update_layout(title_text=('2D quiver'), xaxis=dict(range=(0, W), constrain='domain', visible=False), yaxis=dict(range=(H, 0), visible=False, scaleanchor="x", scaleratio=1)) # background is the ground truth mask overlayed with the rendered image if img_mask_grad is not None: img_mask_grad = img_mask_grad.cpu() # convert to 0-1 img_mask_grad /= eps_denom(2 * img_mask_grad.abs().max()) assert (img_mask_grad.min().item() >= -0.5 and img_mask_grad.max().item() <= 0.5) img_mask_grad = 0.5 + img_mask_grad img = Image.fromarray( np.array(img_mask_grad.squeeze() * 255).astype(dtype=np.uint8)) elif img is not None: img = img.cpu() # overlay two images with a *soft mask img_mask_gt = img_mask_gt.float() mask = (img_mask_gt == 0) img_mask_gt[mask] = 0.35 img_mask_gt[mask == 0] = 0.65 img_mask_gt = img_mask_gt.unsqueeze(-1) if img.ndim == 2: img = img.unsqueeze(-1) overlayed_image = torch.where(img < 0.5, 2 * img * img_mask_gt, 1 - 2 * (1 - img) * (1 - img_mask_gt)) img = Image.fromarray( np.array(overlayed_image.squeeze() * 255).astype(dtype=np.uint8)) else: img_mask_gt = img_mask_gt.float() img = Image.fromarray( np.array(img_mask_gt * 255).astype(dtype=np.uint8)) fig.add_layout_image( dict(source=img, xref="x", yref="y", sizex=img.size[0], sizey=img.size[1], opacity=1.0, x=0, y=0, layer='below')) fig.update_layout(height=800, width=W / H * 800, template="plotly_white") if save_html is not None: os.makedirs(os.path.dirname(save_html), exist_ok=True) # figures_to_html([fig], save_html) fig.write_html(save_html) return fig
#marker={'color': iris["species"], 'symbol': 'circle'}, ), layout_title_text="..." ) fig5 #%% Figure Factories import numpy as np import plotly.figure_factory as ff x1,y1 = np.meshgrid(np.arange(0, 2, .2), np.arange(0, 2, .2)) u1 = np.cos(x1)*y1 v1 = np.sin(x1)*y1 fig6 = ff.create_quiver(x1, y1, u1, v1) fig6.show() #%% Make Subplots from plotly.subplots import make_subplots fig7 = make_subplots(rows=1, cols=2) fig7.add_trace(go.Scatter(y=[4,2,1], mode="lines"), row=1, col=1) fig7.add_trace(go.Bar(y=[2,1,3]), row=1, col=2) fig7 #%% #%% Updating Figures
def render_output(function_digraph): if function_digraph == {}: print("Empty input") return False graph_network = nx.DiGraph() key = 0 # lookup is used to map function to graph_network's first int lookup = {} for i in function_digraph: # Add functions as Nodes and with X,Y positioning graph_network.add_node(key, name=i, x=0, y=0) twopi = math.pi * 2 x0, y0 = math.cos(twopi * key / len(function_digraph)), math.sin( twopi * key / len(function_digraph)) graph_network.add_node(key, name=i, x=x0, y=y0) # Fills lookup lookup[i] = key key += 1 for i in function_digraph: for j in function_digraph[i]: graph_network.add_edge(lookup[i], lookup[j]) # Builds a plotly scatter diagram from the edge connectors edge_trace = Scatter(x=[], y=[], line=Line(width=5, color='#000'), hoverinfo='all', mode='Lines') for edge in graph_network.edges(): # print(edge, G.node[edge[0]]) x0, y0 = graph_network.node[edge[0]]['x'], graph_network.node[ edge[0]]['y'] x1, y1 = graph_network.node[edge[1]]['x'], graph_network.node[ edge[1]]['y'] edge_trace['x'] += [x0, x1, None] edge_trace['y'] += [y0, y1, None] node_trace = Scatter( x=[], y=[], text=[], mode='marker+text', hovertext='None', hoverinfo='text', textfont=dict(size=25, family="Courier New"), marker=Marker( showscale=True, # colorscale options # 'Greys' | 'Greens' | 'Bluered' | 'Hot' | 'Picnic' | 'Portland' | # Jet' | 'RdBu' | 'Blackbody' | 'Earth' | 'Electric' | 'YIOrRd' | 'YIGnBu' colorscale='YIGnBu', reversescale=True, color=[], size=2, colorbar=dict(thickness=15, title='Node Connections', xanchor='left', titleside='right'), line=dict(width=2))) for node in graph_network.nodes(): x, y = graph_network.node[node]['x'], graph_network.node[node]['y'] node_trace['x'].append(x) node_trace['y'].append(y) node_trace['text'].append(graph_network.node[node]['name']) list = [[], [], [], []] for i in (range(int(len((edge_trace['x'])) / 3))): list[0].append(edge_trace['x'][i * 3] + edge_trace['x'][i * 3 + 1] * 0.1) list[1].append(edge_trace['y'][i * 3] + edge_trace['y'][i * 3 + 1] * 0.1) list[2].append( (edge_trace['x'][i * 3 + 1] - edge_trace['x'][i * 3]) * 9) list[3].append( (edge_trace['y'][i * 3 + 1] - edge_trace['y'][i * 3]) * 9) print(list) fig = ff.create_quiver(list[0], list[1], list[2], list[3], arrow_scale=0.1) fig['data'].append(node_trace) offline.plot(fig, filename='networkx.html')
def vector_plot(result, titles, verbose = False, **kwargs): variable = titles['variable'] val0 = list(result.values())[0] # check if this is a 2d vector plot: input and output should have shape 2d if (result[variable].shape == val0.shape) & (val0.shape[1] == 2): if verbose: print('\t 2-d output', result[variable].shape) u = result[variable][:, 0] v = result[variable][:, 1] x = val0[:, 0] y = val0[:, 1] # plotly's quiver plot has its own defaults quiver_defaults = get_defaults(ff.create_quiver) for k, v_ in kwargs.items(): if k in quiver_defaults: quiver_defaults[k] = v_ if verbose: print(quiver_defaults) try: trace = ff.create_quiver( x, y, u, v, name='quiver', line=dict(width=1), **quiver_defaults)['data'][0] # extracts quiver trace except: print('problem with quiver, u,v,x,y shapes:') for v_ in [u, v, x, y]: print(v_.shape) raise layout = go.Layout(title=titles['title'], xaxis=dict(title='x'), yaxis=dict(title='y')) chart_type = '2d-vector' # check if this is a 3d vector plot: input and output should have shape 3d elif (result[variable].shape == val0.shape) & (val0.shape[1] == 3): if verbose: print('\t 3-d output', result[variable].shape, val0.shape) print('\t 3d vector plot') if type(result[variable]) == pd.DataFrame: u = result[variable].values[:, 0].tolist() v = result[variable].values[:, 1].tolist() w = result[variable].values[:, 2].tolist() else: u = result[variable][:, 0].tolist() v = result[variable][:, 1].tolist() w = result[variable][:, 2].tolist() if type(val0) == pd.DataFrame: x = val0.values[:, 0].tolist() y = val0.values[:, 1].tolist() z = val0.values[:, 2].tolist() else: x = val0[:, 0].tolist() y = val0[:, 1].tolist() z = val0[:, 2].tolist() # normalize each vector to get the length norms = np.linalg.norm(result[variable], axis=1) trace = go.Cone( x=x, y=y, z=z, u=u, v=v, w=w, hoverinfo='x+y+z+u+v+w+norm', colorscale='Reds', cmin=0, cmax=norms.max(), ) layout = go.Layout( title=titles['title'], scene=dict( xaxis=dict(title='x'), yaxis=dict(title='y'), zaxis=dict(title='z'), )) chart_type = '3d-vector' else: raise NotImplementedError('plot type not supported yet') return [trace], chart_type, layout
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}")
rowVecY = [] for x in X: desiredPoint = np.array([x, y, z], dtype=float) arrLength = perfectDelta.inverseKinetic(x, y, z) reachedPoint = imperfectDelta.forwardKinetic(*arrLength) rowVecX.append(reachedPoint[0] - desiredPoint[0]) rowVecY.append(reachedPoint[1] - desiredPoint[1]) vecX.append(rowVecX) vecY.append(rowVecY) arrX, arrY = np.meshgrid(X, Y) fig = ff.create_quiver(x=arrX, y=arrY, u=vecX, v=vecY, scale=0.1, arrow_scale=.4, name='quiver', line_width=1) fig.update_layout(title="Error in plan Z = 0", xaxis_title="X in mm", yaxis_title="Y in mm", font=dict(family="Courier New, monospace")) fig.show()
def _process_series(self, series): self._init_cyclers() # if legend=True and both 3d lines and surfaces are shown, then hide the # surfaces color bars and only shows line labels in the legend. # TODO: can I show both colorbars and legends by scaling down the color # bars? show_3D_colorscales = True show_2D_vectors = False for s in series: if s.is_3Dline: show_3D_colorscales = False if s.is_2Dvector: show_2D_vectors = True self._fig.data = [] count = 0 for ii, s in enumerate(series): if s.is_2Dline: line_kw = self._kwargs.get("line_kw", dict()) if s.is_parametric: x, y, param = s.get_data() # hides/show the colormap depending on self._use_cm mode = "lines+markers" if not s.is_point else "markers" if (not s.is_point) and (not self._use_cm): mode = "lines" lkw = dict( name=s.label, line_color=next(self._cl), mode=mode, marker=dict( color=param, colorscale=(next( self._cyccm) if self._use_cyclic_cm( param, s.is_complex) else next(self._cm)), size=6, showscale=self.legend and self._use_cm, colorbar=self._create_colorbar(ii, s.label, True), ), customdata=param, hovertemplate=( "x: %{x}<br />y: %{y}<br />u: %{customdata}" if not s.is_complex else "x: %{x}<br />y: %{y}<br />Arg: %{customdata}"), ) self._fig.add_trace( go.Scatter(x=x, y=y, **merge({}, lkw, line_kw))) else: x, y = s.get_data() x, y, _ = self._detect_poles(x, y) lkw = dict( name=s.label, mode="lines" if not s.is_point else "markers", line_color=next(self._cl), ) self._fig.add_trace( go.Scatter(x=x, y=y, **merge({}, lkw, line_kw))) elif s.is_3Dline: # NOTE: As a design choice, I decided to show the legend entry # as well as the colorbar (if use_cm=True). Even though the # legend entry shows the wrong color (black line), it is useful # in order to hide/show a specific series whenever we are # plotting multiple series. x, y, z, param = s.get_data() if not s.is_point: lkw = dict( name=s.label, mode="lines", line=dict( width=4, colorscale=(next(self._cm) if self._use_cm else self._solid_colorscale()), color=param, showscale=self.legend and self._use_cm, colorbar=self._create_colorbar(ii, s.label, True), ), ) else: lkw = dict(name=s.label, mode="markers", line_color=next(self._cl)) line_kw = self._kwargs.get("line_kw", dict()) self._fig.add_trace( go.Scatter3d(x=x, y=y, z=z, **merge({}, lkw, line_kw))) elif (s.is_3Dsurface and (not s.is_complex)) or (s.is_3Dsurface and s.is_complex and (s.real or s.imag)): xx, yy, zz = s.get_data() # create a solid color to be used when self._use_cm=False col = next(self._cl) colorscale = [[0, col], [1, col]] colormap = next(self._cm) skw = dict( name=s.label, showscale=self.legend and show_3D_colorscales, colorbar=self._create_colorbar(ii, s.label), colorscale=colormap if self._use_cm else colorscale, ) surface_kw = self._kwargs.get("surface_kw", dict()) self._fig.add_trace( go.Surface(x=xx, y=yy, z=zz, **merge({}, skw, surface_kw))) # TODO: remove this? Making it works with iplot is difficult if self._kwargs.get("wireframe", False): line_marker = dict(color=next(self._wfcm), width=2) for i, j, k in zip(xx, yy, zz): self._fig.add_trace( go.Scatter3d( x=i, y=j, z=k, mode="lines", line=line_marker, showlegend=False, )) for i, j, k in zip(xx.T, yy.T, zz.T): self._fig.add_trace( go.Scatter3d( x=i, y=j, z=k, mode="lines", line=line_marker, showlegend=False, )) count += 1 elif s.is_contour and (not s.is_complex): xx, yy, zz = s.get_data() xx = xx[0, :] yy = yy[:, 0] # default values ckw = dict( contours=dict( coloring=None, showlabels=False, ), colorscale=next(self._cm), colorbar=self._create_colorbar(ii, s.label, show_2D_vectors), ) # user-provided values contour_kw = self._kwargs.get("contour_kw", dict()) self._fig.add_trace( go.Contour(x=xx, y=yy, z=zz, **merge({}, ckw, contour_kw))) count += 1 elif s.is_implicit: points = s.get_data() if len(points) == 2: # interval math plotting x, y, pixels = self._get_pixels(s, points[0]) ckw = dict( colorscale=[ [0, "rgba(0,0,0,0)"], [1, next(self._cl)], ], showscale=False, name=s.label, ) contour_kw = self._kwargs.get("contour_kw", dict()) self._fig.add_trace( go.Heatmap(x=x, y=y, z=pixels, **merge({}, ckw, contour_kw))) else: x, y, z, ones, plot_type = points zf = z.flatten() m, M = min(zf), max(zf) col = next(self._cl) # default values ckw = dict( contours=dict( coloring="none" if plot_type == "contour" else None, showlabels=False, type="levels" if plot_type == "contour" else "constraint", operation="<", value=[(m + M) / 2], ), colorscale=[ [0, "rgba(0,0,0,0)"], [1, next(self._cl)], ], fillcolor=col, showscale=True, name=s.label, line=dict(color=col), ) contour_kw = self._kwargs.get("contour_kw", dict()) # TODO: sadly, Plotly does not support yet setting contour # levels, hence the visualization will look ugly whenever # plot_type="contour". # https://github.com/plotly/plotly.js/issues/4503 self._fig.add_trace( go.Contour(x=x, y=y, z=ones, **merge({}, ckw, contour_kw))) count += 1 elif s.is_vector: if s.is_2Dvector: xx, yy, uu, vv = s.get_data() streamlines = self._kwargs.get("streamlines", False) if streamlines: # NOTE: currently, it is not possible to create streamlines with # a color scale: https://community.plotly.com/t/how-to-make-python-quiver-with-colorscale/41028 # default values skw = dict(line_color=next(self._qc), arrow_scale=0.15, name=s.label) # user-provided values stream_kw = self._kwargs.get("stream_kw", dict()) stream = create_streamline(xx[0, :], yy[:, 0], uu, vv, **merge({}, skw, stream_kw)) self._fig.add_trace(stream.data[0]) else: # NOTE: currently, it is not possible to create quivers with # a color scale: https://community.plotly.com/t/how-to-make-python-quiver-with-colorscale/41028 # default values qkw = dict(line_color=next(self._qc), scale=0.075, name=s.label) # user-provided values quiver_kw = self._kwargs.get("quiver_kw", dict()) quiver = create_quiver( xx, yy, uu, vv, **merge({}, qkw, quiver_kw)) # merge two dictionaries self._fig.add_trace(quiver.data[0]) else: xx, yy, zz, uu, vv, ww = s.get_data() streamlines = self._kwargs.get("streamlines", False) if streamlines: seeds_points = get_seeds_points(xx, yy, zz, uu, vv, ww) # default values skw = dict( colorscale=next(self._cm), sizeref=0.3, colorbar=self._create_colorbar(ii, s.label), starts=dict( x=seeds_points[:, 0], y=seeds_points[:, 1], z=seeds_points[:, 2], ), ) # user-provided values stream_kw = self._kwargs.get("stream_kw", dict()) self._fig.add_trace( go.Streamtube(x=xx.flatten(), y=yy.flatten(), z=zz.flatten(), u=uu.flatten(), v=vv.flatten(), w=ww.flatten(), **merge({}, skw, stream_kw))) else: # default values qkw = dict( showscale=(not s.is_slice) or self.legend, colorscale=next(self._cm), sizemode="absolute", sizeref=40, colorbar=self._create_colorbar(ii, s.label), ) # user-provided values quiver_kw = self._kwargs.get("quiver_kw", dict()) self._fig.add_trace( go.Cone(x=xx.flatten(), y=yy.flatten(), z=zz.flatten(), u=uu.flatten(), v=vv.flatten(), w=ww.flatten(), **merge({}, qkw, quiver_kw))) count += 1 elif s.is_complex: if s.is_domain_coloring: x, y, magn_angle, img, colors = s.get_data() xmin, xmax = x.min(), x.max() ymin, ymax = y.min(), y.max() self._fig.add_trace( go.Image( x0=xmin, y0=ymin, dx=(xmax - xmin) / s.n1, dy=(ymax - ymin) / s.n2, z=img, name=s.label, customdata=magn_angle, hovertemplate= ("x: %{x}<br />y: %{y}<br />RGB: %{z}" + "<br />Abs: %{customdata[0]}<br />Arg: %{customdata[1]}" ), )) if colors is not None: # chroma/phase-colorbar self._fig.add_trace( go.Scatter( x=[xmin, xmax], y=[ymin, ymax], showlegend=False, mode="markers", marker=dict( opacity=0, colorscale=[ "rgb(%s, %s, %s)" % tuple(c) for c in colors ], color=[-self.pi, self.pi], colorbar=dict( tickvals=[ -self.pi, -self.pi / 2, 0, self.pi / 2, self.pi, ], ticktext=[ "-π", "-π / 2", "0", "π / 2", "π", ], x=1 + 0.1 * count, title="Argument", titleside="right", ), showscale=True, ), )) if s.coloring == "f": # lightness/magnitude-colorbar self._fig.add_trace( go.Scatter( x=[xmin, xmax], y=[ymin, ymax], showlegend=False, mode="markers", marker=dict( opacity=0, colorscale=[[0, "black"], [1, "white"]], color=[0, 1e20], colorbar=dict( tickvals=[0, 1e20], ticktext=["0", "∞"], x=1 + 0.1 * (count + 1), title="Magnitude", titleside="right", ), showscale=True, ), )) count += 2 else: xx, yy, mag_angle, colors, colorscale = s.get_data() mag, angle = mag_angle[:, :, 0], mag_angle[:, :, 1] if s.coloring != "a": warnings.warn( "Plotly doesn't support custom coloring " + "over surfaces. The surface color will show the " + "argument of the complex function.") # create a solid color to be used when self._use_cm=False col = next(self._cl) colorscale = [[0, col], [1, col]] colormap = next(self._cm) if not s.is_complex else next( self._cyccm) skw = dict( name=s.label, showscale=self.legend and show_3D_colorscales, colorbar=dict( x=1 + 0.1 * count, title=s.label, titleside="right", ), colorscale=colormap if self._use_cm else colorscale, surfacecolor=angle, customdata=angle, hovertemplate= "x: %{x}<br />y: %{y}<br />Abs: %{z}<br />Arg: %{customdata}", ) m, M = min(angle.flatten()), max(angle.flatten()) # show pi symbols on the colorbar if the range is close # enough to [-pi, pi] if (abs(m + self.pi) < 1e-02) and (abs(M - self.pi) < 1e-02): skw["colorbar"]["tickvals"] = [ m, -self.pi / 2, 0, self.pi / 2, M, ] skw["colorbar"]["ticktext"] = [ "-π", "-π / 2", "0", "π / 2", "π", ] surface_kw = self._kwargs.get("surface_kw", dict()) self._fig.add_trace( go.Surface(x=xx, y=yy, z=mag, **merge({}, skw, surface_kw))) count += 1 elif s.is_geometry: x, y = s.get_data() lkw = dict(name=s.label, mode="lines", fill="toself", line_color=next(self._cl)) line_kw = self._kwargs.get("line_kw", dict()) self._fig.add_trace( go.Scatter(x=x, y=y, **merge({}, lkw, line_kw))) else: raise NotImplementedError("{} is not supported by {}".format( type(s), type(self).__name__))
def vector_field(field2d, settings): assert isinstance(field2d, (CenteredGrid, StaggeredGrid)) if isinstance(field2d, StaggeredGrid): field2d = field2d.at_centers() assert isinstance(field2d, CenteredGrid) assert field2d.spatial_rank == 2 batch = settings.get('batch', 0) batch = min(batch, field2d.values.shape.batch.volume) arrow_origin = settings.get('arrow_origin', 'tip') assert arrow_origin in ('base', 'center', 'tip') max_resolution = settings.get('max_arrow_resolution', 40) max_arrows = settings.get('max_arrows', 2000) min_arrow_length = settings.get('min_arrow_length', 0.005) * math.max(field2d.box.size) draw_full_arrows = settings.get('draw_full_arrows', False) x, y = field2d.points.vector.unstack_spatial('x,y', to_numpy=True) data = math.join_dimensions(field2d.values, field2d.shape.batch, 'batch').batch[batch] data_x, data_y = data.vector.unstack_spatial('x,y', to_numpy=True) while np.prod(x.shape) > max_resolution ** 2: y = y[::2, ::2] x = x[::2, ::2] data_y = data_y[::2, ::2] data_x = data_x[::2, ::2] y = y.flatten() x = x.flatten() data_y = data_y.flatten() data_x = data_x.flatten() if max_arrows is not None or min_arrow_length > 0: length = np.sqrt(data_y**2 + data_x**2) keep_indices = np.argsort(length) keep_indices = keep_indices[length[keep_indices] > min_arrow_length] if len(keep_indices) > max_arrows: keep_indices = keep_indices[-max_arrows:] y = y[keep_indices] x = x[keep_indices] data_y = data_y[keep_indices] data_x = data_x[keep_indices] if len(x) == 0: return EMPTY_FIGURE if arrow_origin == 'tip': x -= data_x y -= data_y elif arrow_origin == 'center': x -= 0.5 * data_x y -= 0.5 * data_y lower = field2d.bounds.lower.vector.unstack_spatial('x,y', to_python=True) upper = field2d.bounds.upper.vector.unstack_spatial('x,y', to_python=True) x_range = [lower[0], upper[0]] y_range = [lower[1], upper[1]] if draw_full_arrows: result = plotly_figures.create_quiver(x, y, data_x, data_y, scale=1.0) # 7 points per arrow result.update_xaxes(range=x_range) result.update_yaxes(range=y_range) return result else: lines_y = np.stack([y, y + data_y, [None] * len(x)], -1).flatten() # 3 points per arrow lines_x = np.stack([x, x + data_x, [None] * len(x)], -1).flatten() return { 'data': [ { 'mode': 'lines', 'x': lines_x, 'y': lines_y, 'type': 'scatter', } ], 'layout': { 'xaxis': {'range': x_range}, 'yaxis': {'range': y_range}, } }
def _update_interactive(self, params): for i, s in enumerate(self.series): if s.is_interactive: self.series[i].update_data(params) if s.is_2Dline and s.is_parametric: x, y, param = self.series[i].get_data() self.fig.data[i]["x"] = x self.fig.data[i]["y"] = y self.fig.data[i]["marker"]["color"] = param self.fig.data[i]["customdata"] = param elif s.is_2Dline: x, y = self.series[i].get_data() x, y, _ = self._detect_poles(x, y) if s.is_geometry: self.fig.data[i]["x"] = x self.fig.data[i]["y"] = y elif s.is_3Dline: x, y, z, param = s.get_data() self.fig.data[i]["x"] = x self.fig.data[i]["y"] = y self.fig.data[i]["z"] = z self.fig.data[i]["line"]["color"] = param elif s.is_3Dsurface and s.is_parametric: x, y, z = self.series[i].get_data() self.fig.data[i]["x"] = x self.fig.data[i]["y"] = y self.fig.data[i]["z"] = z elif (s.is_3Dsurface and (not s.is_complex)) or (s.is_3Dsurface and s.is_complex and (s.real or s.imag)): x, y, z = self.series[i].get_data() self.fig.data[i]["z"] = z elif s.is_contour and (not s.is_complex): _, _, zz = s.get_data() self.fig.data[i]["z"] = zz elif s.is_implicit: points = s.get_data() if len(points) == 2: raise NotImplementedError else: _, _, zz, ones, _ = points self.fig.data[i]["z"] = ones elif s.is_vector and s.is_3D: streamlines = self._kwargs.get("streamlines", False) if streamlines: raise NotImplementedError _, _, _, u, v, w = self.series[i].get_data() self.fig.data[i]["u"] = u.flatten() self.fig.data[i]["v"] = v.flatten() self.fig.data[i]["w"] = w.flatten() elif s.is_vector: x, y, u, v = self.series[i].get_data() streamlines = self._kwargs.get("streamlines", False) if streamlines: streams = create_streamline(x[0, :], y[:, 0], u, v) data = streams.data[0] # TODO: iplot doesn't work with 2D streamlines. Why? # Is it possible that the sequential update of x and y # is the cause of the error? Since at every update, # len(x) = len(y) but those are different from before. raise NotImplementedError else: # default values qkw = dict(line_color=self.quivers_colors[i], scale=0.075, name=s.label) # user-provided values quiver_kw = self._kwargs.get("quiver_kw", dict()) quivers = create_quiver(x, y, u, v, **merge({}, qkw, quiver_kw)) data = quivers.data[0] self.fig.data[i]["x"] = data["x"] self.fig.data[i]["y"] = data["y"] elif s.is_complex: if s.is_domain_coloring: raise NotImplementedError # TODO: for some unkown reason, domain_coloring and # interactive plot don't like each other... # x, y, z, magn_angle, img, discr, colors = self._get_image(s) # self.fig.data[i]["z"] = img # self.fig.data[i]["x0"] = -4 # self.fig.data[i]["y0"] = -5 # # self.fig.data[i]["customdata"] = magn_angle else: xx, yy, mag_angle, colors, colorscale = s.get_data() mag, angle = mag_angle[:, :, 0], mag_angle[:, :, 1] self.fig.data[i]["z"] = mag self.fig.data[i]["surfacecolor"] = angle self.fig.data[i]["customdata"] = angle m, M = min(angle.flatten()), max(angle.flatten()) # show pi symbols on the colorbar if the range is close # enough to [-pi, pi] if (abs(m + self.pi) < 1e-02) and (abs(M - self.pi) < 1e-02): self.fig.data[i]["colorbar"]["tickvals"] = [ m, -self.pi / 2, 0, self.pi / 2, M, ] self.fig.data[i]["colorbar"]["ticktext"] = [ "-π", "-π / 2", "0", "π / 2", "π", ] elif s.is_geometry and not (s.is_2Dline): x, y = self.series[i].get_data() self.fig.data[i]["x"] = x self.fig.data[i]["y"] = y