How is it possible to color a 3D shape /point cloud (in my case a human body), in such a way that each point has a different color but the color transition from point to point is smooth, as shown in the picture below?
The shape of N points is represented as an Nx3 array of point coordinates x,y,z. I tried to simply convert the coordinate values x,y,z of each point to r,g,b color values, but the result isn't satisfying (e.g. some points that are close to each other according to the Euclidean distance are colored by a similar color but they should be colored with different colors because their geodesic distance is large).
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
pc = ...
colors = (pc - pc.min()) / (pc.max() - pc.min())
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(pc[1], pc[1], pc[2], c=colors)
plt.show()
I found a way to do it which gives a satisfying result.
The idea is to color a sphere based on the coordinates of its vertices (as shown in the question). Such a coloring is nice because there are no problems with "Euclidean vs geodesic distance" as in human shapes.
Then, we can use Pytorch3D to deform the sphere to the input shape as described here. In this way the sphere coloring is smoothly transferred to the human shape. Although I have a point cloud with only vertex coordinates, the result is pretty good.
Below is an example of coloring a dolphin by using this method:
One problem is that we still need to transfer the coloring from the obtained shape to the original shape, something that perhaps could be done by finding nearest neighbors between the two (I haven't tried it though).
Related
I have a plot with several curves that looks like this:
These curves start from the top right corner and finish around the point (0.86, 0.5).
I want to focus attention on the end point. If I zoom on this region, it is still not very easy to distinguish the different lines because they overlap several times.
My idea is then to add a gradient of opacity so that the curves would be transparent at their start point and then, the opacity would increasing as we get closer to the end point.
How would you do that with matplotlib?
Currently, I just basically do for the three curves:
plt.plot( r, l )
with r, l being two arrays.
You could always break down your x and y arrays into smaller arrays that you plot separately. This would give you the opportunity to modify alpha for each segment.
See example below:
import numpy as np
import matplotlib.pyplot as plt
N_samp=1000
x=np.arange(N_samp)
y=np.sin(2*np.pi*x/N_samp)
step=10
[plt.plot(x[step*i:step*(i+1)],y[step*i:step*(i+1)],alpha=np.min([0.1+0.01*i,1]),color='tab:blue',lw=1) for i in range(int(N_samp/step))]
plt.show()
I have two arrays (vel_y,vel_z) representing velocities in the y and z directions, respectively, that are both shaped as (512,512) that I am attempting to represent using a quiver plot.
Here is how I plotted the quiver:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,512,num=512)
[X,Y] = np.meshgrid(x,x)
fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,vel_y,vel_z,np.arctan2(vel_z,vel_y),pivot='mid',units='x',scale=2)
The arctan2() call is so that different orientations are colored differently as in this answer.
Obviously plotting all 5122 of these arrows makes for a jumbled and difficult to parse plot, which you can see here:
Quiver Plot.
I was wondering if there was a better way to scale/represent the arrows so that it is more readable?
However, the main question I have is how I could 'downsample' this velocity information to go from plotting 5122 arrows to 1002 for example. Would this require interpolation between points where the velocity is defined?
Thank you!
The simple way to do this is simply to take one point over N in each vectors given to quiver.
For a given np.array, you can do this using the following syntax: a[::N]. If you have multiple dimensions, repeat this in each dimension (you can give different slip for each dimension): a[::N1, ::N2].
In your case:
N1 = 5
N2 = 5
ax.quiver(X[::N1, ::N2], Y[::N1, ::N2], vel_y[::N1, ::N2], vel_z[::N1, ::N2], np.arctan2(vel_z,vel_y)[::N1, ::N2], pivot='mid',units='x',scale=2)
You don't need interpolation, unless you want to plot velocities at points not defined in the grid where you have your measurements/simulations/whatever.
Might be a strange question, but I am wondering if it's possible to replace a 2d matrix made up of ones and zeros with a scatter plot of say, black dots where all the ones are but nothing for zeros:
Unfortunately I don't have the best reproducible answer, but I have a 2D array made up for zeros and ones (size 275 and 357):
I am hoping to basically cover the areas that are made up of ones with small black dots (assuming in the form of a scatter plot which will later be overlayed on another contour plot):
The original contour plot is on the left and the idea I'm going for is on the right (picture more black dots just on the areas made up of ones):
I tried making a reproducible array here:
#array of ones and zeros
array = np.array(([0,0,0,0,0,0,1,1,0,0,0,1,1,1], [0,1,0,0,0,1,0,0,0,0,0,1,0,1]))
plt.pcolormesh(array)
I tried using this as an example and apply it to the 2D array, but getting some errors?
# as an example, borrowed from: https://stackoverflow.com/questions/41133419/how-to-do-the-scatter-plot-for-the-lists-or-2d-array-or-matrix-python
X=[[0,3,4,0,1,1],
[0,0,0,5,1,1],
[6,7,0,8,1,1],
[3,6,1,5,6,1]]
Y=[12,15,11,10]
x_arr = np.array(X)
y = np.array(Y)
fig, ax = plt.subplots()
#colors=list('bgrcmykw')
for i, x in enumerate(x_arr.T):
ax.scatter(x,y, c='k',s=5)
plt.show()
My goal is to basically convert this 2d matrix made up of ones and zeros to a scatter plot or some sort of graph where the ones are made up of black dots and the zeros have nothing. This will later be overlaid on another contour plot. how might I go about setting the ones to a scatter plot made up of black dots?
Here's what I would do. I didn't plot all the points to reduce the computational demand of creating the figure. you might want to do that if you have a lot of points to plot. either way, you can change that according to your need.
import numpy as np
from matplotlib import pyplot as plt
np.random.seed(0)
mask = np.random.randint(0, 2, (20, 20))
ys, xs = np.where(mask.astype(bool))
plt.imshow(mask)
plt.scatter(xs[::2], ys[::2])
output:
How does the area of the circular marker scale with the marker radius in Matplotlib? I would expect it to scale as pi times radius squared, but it does not.
I am trying to create a figure to show a closely packed distribution of N circles. This distribution happens to be regular (it is hexagonal) so it’s easy to know the locations of the centres of each of the circles. I plot these using matplotlib.pyplot.scatter(), using the circle marker from matplotlib/lib/matplotlib/markers.py for the circles.
Now in order to pack the circles closely, I need to set the area of the circular markers so that they precisely touch each other. I expect this to happen if I set the marker area to numpy.pi*(L/2)**2 where L is the diameter of each circle (in points), which is equal to the distance between two circles if they are to touch precisely. But this results in a plot in which the circles overlap. Here is the code that produces this plot:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
f = plt.figure(figsize=(7, 7), dpi=100)
ax = f.add_subplot(1,1,1)
ax.set_ylim(-105,105)
ax.set_xlim(-105,105)
L = 14.0 # Diameter of a circle in data units
# marker_radius is L/2 in points.
marker_radius = (ax.transData.transform((0,0))
-ax.transData.transform((L/2,0)))[0]
marker_area = np.pi*marker_radius**2
ax.scatter(x, y, color='#7fc97f', edgecolors='None', s=marker_area)
plt.savefig('figure.png',bbox_inches='tight')
Clearly the area of the circular marker in matplotlib/lib/matplotlib/markers.py does not scale as pi times radius squared (as it should). Upon trial and error, I found that it actually scales as roughly 2.3 times radius squared. When I set the marker_area to 2.3*marker_radius**2, I get a closely packed distribution as required.
I wonder if somebody could comment on why the circular marker size scales in this peculiar way. Also, what is the precise scaling? Is it really 2.3? Thanks!
I quickly tried this code (changing only the marker from s to o), and from that it seems that the square root of the marker size equals the diameter (in points, see the post I referred to) of the circle:
From the documentation:
s : scalar or array_like, shape (n, ), optional, default: 20 size in points^2.
I have a 64x360 Matrix of values belonging to radial and azimuthal coordinates. I want to visualize them in two plots: a cartesian and a polar plot.
I visualized the heatmap in cartesian coordinates using imshow():
import numpy as np
import matplotlib.pyplot as plt
P=np.loadtxt('Pdata.csv')
print np.shape(P)
plt.imshow(P)
plt.xlabel('radius')
plt.ylabel('theta')
plt.show()
This gives me the desired plot:
The same plot in polar coordinates was also pretty straigh forward using pcolor():
r=np.arange(0,np.shape(P)[1],1)
t=np.arange(0,np.shape(P)[0],1)
R,T = np.meshgrid(r,t)
fig = plt.figure()
ax = fig.add_subplot(111, polar = True)
ax.pcolor(T,R,P)
plt.show()
However, I am not really satisfied with the result:
The resolution of the plot seems to be pretty limited so that it's not possible to distinguish between angles with higher intensity and lower intensity, as it is in the cartesian plot. The whole solid angle seems to be divided into six or seven "cake wedges" only. Is there an easy and pythonic way to enhance the angular resolution?
Ok, I found out something. It works with:
t = np.radians(np.linspace(0, np.shape(P)[0],np.shape(P)[0]))
r = np.arange(0, np.shape(P)[1], 1)
Just as seen here: Polar contour plot in matplotlib - best (modern) way to do it?