I am trying to plot a polar colour heat map for a set of coordinates (coor) and corresponding phi values. I have used the tripcolor function as follows:
plt.tripcolor(coor[:, 0], coor[:, 1], phi, shading=shading, cmap=cmap, edgecolor="face")
plt.show()
This is the result that I got:
PlotMesh
Is there a way to make the outer grid circular?
I would try to create a triangulation from the coordinates:
import matplotlib.tri as tri
triang = tri.Triangulation(coor[:, 0], coor[:, 1])
plt.tripcolor(triang, phi, shading=shading, cmap=cmap, edgecolor="face")
Related
I have a 3d triangle mesh
from torch_geometric.data import Data
want to plot it as depth map from top view, so the pixel value of (x,y) equals depth value.
there is a piece of code to plot, but I don't know how to calculate z value for each pair of (x,y)
plt.subplot()
x = data.x[:,1]
y = data.x[:,0]
X, Y = np.meshgrid(x, y)
plt.pcolor(data.x[:,1], data.x[:,0], data.x[:,2] * 255, cmap='RdBu', vmin=0, vmax=255)
You probably want to use tripcolor.
Simply cut off the z-component from your data and use z as the value in your plot:
tpc = ax1.tripcolor(triang, z, shading='flat')
I am unable to understand from the matplotlib documentation(https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html), the working of a trisurf plot. Can someone please explain how the X,Y and Z arguments result in a 3-D plot?
Let me talk you through this example taken from the docs
'''
======================
Triangular 3D surfaces
======================
Plot a 3D surface with a triangular mesh.
'''
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
n_radii = 8
n_angles = 36
# Make radii and angles spaces (radius r=0 omitted to eliminate duplication).
radii = np.linspace(0.125, 1.0, n_radii)
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)
# Repeat all angles for each radius.
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
# Convert polar (radii, angles) coords to cartesian (x, y) coords.
# (0, 0) is manually added at this stage, so there will be no duplicate
# points in the (x, y) plane.
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())
# Compute z to make the pringle surface.
z = np.sin(-x*y)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_trisurf(x, y, z, linewidth=0.2, antialiased=True)
plt.show()
The x, y values are a range of values over which we calculate the surface. For each (x, y) pair of coordinates, we have a single value of z, which represents the height of the surface at that point.
I have measured the positions of different products in different angles positions (6 values in steps of 60 deg. over a complete rotation). Instead of representing my values on a Cartesian graph where 0 and 360 are the same point, I want to use a polar graph.
With matplotlib, I got a spider chart type graph, but I want to avoid straight lines between points and display and extrapolated values between those. I have a solution that is kind of OK, but I was hoping there is a nice "one liner" I could use to have a more realistic representation or a better tangent handling for some points.
Does anyone have an idea to improve my code below ?
# Libraries
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Some data to play with
df = pd.DataFrame({'measure':[10, -5, 15,20,20, 20,15,5,10], 'angle':[0,45,90,135,180, 225, 270, 315,360]})
# The few lines I would like to avoid...
angles = [y/180*np.pi for x in [np.arange(x, x+45,5) for x in df.angle[:-1]] for y in x]
values = [y for x in [np.linspace(x, df.measure[i+1], 10)[:-1] for i, x in enumerate(df.measure[:-1])] for y in x]
angles.append(360/180*np.pi)
values.append(values[0])
# Initialise the spider plot
ax = plt.subplot(polar=True)
# Plot data
ax.plot(df.angle/180*np.pi, df['measure'], linewidth=1, linestyle='solid', label="Spider chart")
ax.plot(angles, values, linewidth=1, linestyle='solid', label='what I want')
ax.legend()
# Fill area
ax.fill(angles, values, 'b', alpha=0.1)
plt.show()
the result is below, I want something similar to the orange line with some kind of spline to avoid sharp corners I currently get
I have a solution that is a patchwork of other solutions. It needs to be cleaned and optimized, but it does the job !
Comments and improvements are always welcome, see below
# https://stackoverflow.com/questions/33962717/interpolating-a-closed-curve-using-scipy
from scipy import interpolate
x=df.measure[:-1] * np.cos(df.angle[:-1]/180*np.pi)
y=df.measure[:-1] * np.sin(df.angle[:-1]/180*np.pi)
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]
# fit splines to x=f(u) and y=g(u), treating both as periodic. also note that s=0
# is needed in order to force the spline fit to pass through all the input points.
tck, u = interpolate.splprep([x, y], s=0, per=True)
# evaluate the spline fits for 1000 evenly spaced distance values
xi, yi = interpolate.splev(np.linspace(0, 1, 1000), tck)
def cart2pol(x, y):
rho = np.sqrt(x**2 + y**2)
phi = np.arctan2(y, x)
return(rho, phi)
# Initialise the spider plot
plt.figure(figsize=(12,8))
ax = plt.subplot(polar=True)
# Plot data
ax.plot(df.angle/180*np.pi, df['measure'], linewidth=1, linestyle='solid', label="Spider chart")
ax.plot(angles, values, linewidth=1, linestyle='solid', label='Interval linearisation')
ax.plot(cart2pol(xi, yi)[1], cart2pol(xi, yi)[0], linewidth=1, linestyle='solid', label='Smooth interpolation')
ax.legend()
# Fill area
ax.fill(angles, values, 'b', alpha=0.1)
plt.show()
I am trying to rotate a given figure 90 degree.
fig = plt.figure()
points = [[0.3036, 0.1960], [0.6168, 0.2977], [0.7128, 0.4169], [0.7120, 0.1960],[0.9377,0.2620],\
[0.7120,0.5680],[0.3989,0.6697],[0.3028,0.7889],[0.3036,0.5680],[0.5293,0.5020]]
bird = matplotlib.patches.Polygon(points, facecolor='blue')
fig, ax = plt.subplots()
ax.set_aspect("equal")
ax.add_patch(bird)
ax.set_xlim(0.2,1)
ax.set_ylim(0.2,0.9)
plt.show()
To rotate a matrix, you basically multiply your coordinates with a rotation matrix, that is given by
[[cos(theta), -sin(theta)], [sin(theta), cos(theta)]]
theta being the angle of rotation (so in your case [[0, -1], [1, 0]]).
So you just calculate the dot product like this:
points = np.array(points)
rotation_matrix = np.array([[0, -1], [1, 0]])
new_points = points.dot(rotation_matrix)
and then you can plot your new set of coordinates. This is the results (after adding (0, 1) to the coordinates so that the bird is in the frame...
There are two points on the stereographic projection as shown in the figure:
These points are supposed to be on the end points of a dimeter of a circle. How to draw a circle passing through these two points?
Code for the above plot:
import matplotlib.pylab as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
from scipy.interpolate import splev, splrep
# create instance of basemap, note we want a south polar projection to 90 = E
myMap = Basemap(projection='spstere',boundinglat=0,lon_0=180,resolution='l',round=True,suppress_ticks=True)
# set the grid up
gridX, gridY = 10.0, 15.0
parallelGrid = np.arange(-90.0,90.0,gridX)
meridianGrid = np.arange(-180.0,180.0,gridY)
# draw parallel and meridian grid, not labels are off. We have to manually create these.
myMap.drawparallels(parallelGrid,labels=[False,False,False,False])
myMap.drawmeridians(meridianGrid,labels=[False,False,False,False],labelstyle='+/-',fmt='%i')
# plot azimuth labels, with a North label.
ax = plt.gca()
ax.text(0.5,1.025,'N',transform=ax.transAxes,horizontalalignment='center',verticalalignment='bottom',size=25)
for para in np.arange(gridY,360,gridY):
x= (1.1*0.5*np.sin(np.deg2rad(para)))+0.5
y= (1.1*0.5*np.cos(np.deg2rad(para)))+0.5
ax.text(x,y,u'%i\N{DEGREE SIGN}'%para,transform=ax.transAxes,horizontalalignment='center',verticalalignment='center')
summerAzi = np.array([0, 360])
summerAlt = np.array([40, 4])
summerX, summerY = myMap(summerAzi, -summerAlt)
summerX_new = np.linspace(summerX.min(), summerX.max(),30)
summerY_smooth = splev(summerX_new, splrep(summerX, summerY, k=1))
myMap.plot(summerX_new, summerY_smooth, 'g')
myMap.plot(summerX, summerY, 'go')
plt.show()
Inbuilt tissot() function is good enough to plot circles on a conformal projections (as in this case). On non-conformal projections, it plots ellipses.
Here the mid point of the tissot indicatrix is (0, -22) in degrees.
Its radius = (40-4)/2 = 18 in degrees.
Number of points = 36 is fine.
The relevant code is:
myMap.tissot(0, -22, 18, 36, \
facecolor='none', \
edgecolor='#ff0000', \
linewidth=1, \
alpha=1)
The circle in this polar representation will not look like a circle on a rectangular grid (i.e. "round"). Apart from that you can draw a circle just as you would on the cartesian plane, starting in polar coordinates, transforming to cartesian coordinates, offset the center and use the plot function.
summerAzi = np.array([0, 360])
summerAlt = -np.array([40, 4])
summerX, summerY = myMap(summerAzi, summerAlt)
phi = np.linspace(0,2.*np.pi)
r = np.abs(np.diff(summerAlt))/2.
x = r*np.cos(phi)
y = -r*np.sin(phi)+summerAlt.mean()
X,Y= myMap(x,y)
myMap.plot(X,Y, color="crimson")
myMap.plot(summerX, summerY, color="gold", marker="o")