I have to make the following scatterplot in python. The code for this plot is :
n = 1024
X = np.random.normal(0,1,n)
Y = np.random.normal(0,1,n)
plt.scatter(X,Y)
But as espected, this wont give the colours. I've tried a lot, but can't find the solution. I know it has something to do with the angle of X/Y in the plot, but can't find out how to do this.
The logic is most likely angle from origo to point. This can be calculated easily with np.arctan2(X, Y). I don't know which colormap that is used in your example but you can probably find it here: https://matplotlib.org/examples/color/colormaps_reference.html
Use the angles of the points to the c keyword in plt.scatter
To get something similar to your example:
plt.scatter(X,Y, c=np.arctan2(X, Y), cmap='rainbow', s=50, alpha=0.8)
Related
I am a beginner in Python and I'll try to visualize a function depending on x and y. With the contour plot the maximum should be seen easier.
That is my code and the output. The question comes below.
# Generate synthetic plot
x_fine=np.linspace(-4,10,100).reshape(-1,1)
y_fine=np.linspace(-3,3,100)
f_xy=1.5*np.sin(x_fine) - 0.1*(x_fine-3)**2 +10 - 0.5*(y_fine**2-2) + np.sin(y_fine)*2
#f_xy= -(x_fine-2)**2 - (y_fine)**2 +20
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(x_fine, y_fine, f_xy, cmap=cm.coolwarm, linewidth=0, antialiased=False, alpha=0.6)
ax.contourf(x_fine.flatten(),y_fine, f_xy, zdir='z', offset=-0, cmap=cm.coolwarm,alpha=0.7)
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.set_zlabel("Objective")
plt.show()
So, if you might see, the plot contour plot reveals the contours, but somehow rotated by 90 degrees. If I just change the x and y input in the contour plot method, the graphs deforms. If I change the x and y input both in the contour plot and in the plot_surface command, the graph is shown correctly. But then, I need declare my x-axis as "y" and vice versa, which I would like to avoid.
I hope I made my problem clear. I am interested in reading your answers what I might have done wrong or why the code behaves as is behaves :D
In numpy, the axes are ordered row-column, e.g.
a = np.zeros((3, 2))
a
>>> [[0, 0],
[0, 0],
[0, 0]]
When you reshape x_fine to (-1, 1) you give it a width of 1 and a height of N. Something like.
x_fine
>> [[-4],
[-3.96],
...
[10]]
Following the convention of x across and y up/down, this is the wrong orientation.
Put the reshap(-1, 1) on y_fine instead. Then when you draw the contours call flatten() on y_fine instead of x_fine.
Now the two plots are orientated the same. If you want to verify that they are rotated correctly, and not BOTH off by 90 degrees, set f_xy to something simple like f_xy = x_fine + np.zeros_like(y_fine) and you'll see both increasing in the x direction.
I try to make simple 3D plot with plot_surface of matplotlib, below is the minimum example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
x_test = np.arange(0.001, 0.01, 0.0005)
y_test = np.arange(0.1, 100, 0.05)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
Xtest, Ytest = np.meshgrid(x_test, y_test)
Ztest = Xtest**-1 + Ytest
surf = ax.plot_surface(Xtest, Ytest, Ztest,
cmap=cm.plasma, alpha=1,
antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
ax.set_ylabel(r'$ Y $', fontsize=16)
ax.set_xlabel(r'$ X $', fontsize=16)
ax.set_zlabel(r'$ Z $', fontsize=16)
The result gives strange colormap, that does not represent the magnitude of the z scale, as you can see from here 3D plot result.
I mean if you take a straight line of constant Z, you don't see the same color.
I've tried to change the ccount and rcount inside plot_surface function or changing the interval of the Xtest or Ytest data, nothing helps.
I've tried some suggestion from here and here. But it seems not related.
Could you help me how to solve this? It seems a simple problem, but I couldn't solve it.
Thanks!
Edit
I add example but using the original equation that I don't write it here (it's complicated), please take a look: Comparison.
While the left figure was done in Matlab (by my advisor),
the right figure by using matplotlib.
You can see clearly the plot on the left really make sense,
the brightest color always on the maximum z-axis. Unfortunately, i don't know matlab. I hope i can do it by using python,
Hopefully this edit makes it more clear of the problem.
Edit 2
I'm sure this is not the best solution. That's why I put it here, not as an answer. As suggested by #swatchai to use the contour3D.
Since surface is set of lines, I can generate the correct result by plotting a lot of contour lines, by using:
surf = ax.contour3D(Xtest, Ytest, Ztest, 500, cmap=cm.plasma,
alpha=0.5, antialiased=False)
The colormap is correct as you can see from herealternative1
But the plot is very heavy. When you zoom-in, it doesn't look good, unless you increase again the number of the contour.
Any suggestion are welcome :).
I don't know how this can be achieved but maybe some words on why this is happening.
plot_surface generates a mesh where the vertices are defined by x and y and z.
Each patch has 4 corners and gets a color corresponding to its z value. Looking at the plot it
could be the maximal z value of the 4 corners (just a guess).
And if you look closely the colors of the patches actually do get lighter as you move in +y direction.
But what is far more obvious are the color changes in x direction, producing the slopes you mentioned.
But this can not be avoided if each patch has just a single color.
You can see this maybe more clearly if you change the formula to Z = (X**-1 + 10 * Y)
The behavior of the surface plot is not what you expect. Only contour3D or contourf3D can display such behavior. Here is relevant code that you can try to get the plot that follows:
surf = ax.plot_surface(Xtest, Ytest, Ztest, cmap=cm.plasma, alpha=0.55)
ax.contourf3D(Xtest, Ytest, Ztest, cmap=cm.plasma)
The plot that show both surface and contourf3D:
I guess, the formal answer to plot this kind of surface is by using Axes3D.contour and Axes3D.contourf. Based on documentation
, for example:
surf2 = ax.contourf(Xtest, Ytest, Ztest, 250, cmap=cm.plasma,
alpha=0.6, antialiased=False)
surf = ax.contour(Xtest, Ytest, Ztest, 250, cmap=cm.plasma,
alpha=0.6, antialiased=False)
The result is here. The colormap shows correct z-scale.
It's not as perfect as smooth surface, as it depends on how much we zoom it or how much we put the contour. I don't know if there's a way to create this by plot_surface. thanks #swatchai.
I have several thousand points with X,Y,C values (in numpy arrays).
I want each X,Y point to be plotted on a 2D image plot with a colored square around it (a box of size 40x40 units). Each X,Y point should be centered in the middle of the box. The colour of the box will be mapped according to the C value. The X,Y points are fairly randomly spaced. The points are arranged so that no boxes will overlap, they may touch, or have gaps.
I'm not a Python expert so would appreciate if someone could help get me started on this with a few lines of code. I believe that something like imshow or pcolor will be needed.
Thanks,
You can simply set up the size and marker type in the scatter command.
That'd be my solution:
X = 50 * np.round(10 * np.random.rand(100))
Y = 50 * np.round(10 * np.random.rand(100))
C = np.random.rand(100)
plt.figure(figsize=(12, 12))
sc = plt.scatter(X, Y, s=40**2, c=C, marker='s', cmap='gist_rainbow')
plt.scatter(X, Y, s=11**2, c='k')
plt.colorbar(sc)
plt.axis('equal')
plt.show()
The output would be the following:
Hope that helps!
I've seen quite a few questions along the same vein as this one but they always seem to diverge a little before they answer my question exactly or I can apply them.
I am looking to plot error bars in the same colour scheme as my scatter graph points. If my values were plotted on an x and y axis and I wished them to vary colour with another Z value logarithmically, currently I have:
c = np.abs(zVals)
cmhot = plt.get_cmap("plasma")
sc.set_clim(vmin=min(zVals), vmax=max(zVals))
sc = plt.scatter(xVals, yVals, c=c, norm=mplc.LogNorm(),
s=50, cmap=cmhot, edgecolors='none')
###This section all works fine, it is when I introduce the error bars I struggle
norm = mplc.LogNorm(vmin=min(zVals), vmax=max(zVals)
plt.errorbar(xVals, yVals, yerr = [negyVals,posyVals], c=cmhot(norm(zVals)))
plt.colorbar(sc)
plt.ylim([-10,110])
plt.xlim([1,100])
plt.xscale('log')
plt.show()
This results in an error of the form:
ValueError: to_rgba: Invalid rgba arg ... length of rgba sequence should be either 3 or 4
I am quite confused with the colour situation in general so any help would be much appreciated at the moment. Cheers.
I think this is surprisingly hard to do in matplotlib. The only way I've found is to use a for loop, and plot each point individually.
For example
plt.figure()
#data
x=np.linspace(-10, 10, 100)
y=np.cos(x)
y_error=0.2+0.5*np.random.randn(len(x))
z=np.linspace(0, 10, 100)
cm=plt.get_cmap('plasma')
plt.scatter(x, y, c=z_values, cmap=cm, zorder=10)
for i, (xval, yval, y_error_val, zval) in enumerate(zip(x, y, y_error, z)):
#Get the colour from the colourmap
colour=cm(1.0*zval/np.max(z))
#(could also just do colour=cm(1.0*i/len(x)) here)
#(Or Norm(zval) in your case)
plt.errorbar(xval, yval, yerr=y_error_val, linestyle='', c=colour)
plt.show()
which gives this plot
Obviously this won't be very efficient for large numbers of points!
I am trying to plot the solutions of a minimization problem,
'X, Y = meshgrid(gammas, psis)'
gammas and psis are my 2 axes,
'mplot3d(X, Y, x)'
x is the solution of my problem,
While executing my script : name 'mplot3d' is not defined......
import pylab
def scatterme(x, y, z):
pylab.figure()
imi = pylab.scatter(x, y, c = z, edgecolor = "none")
pylab.colorbar(imi)
pylab.show()
In this case, my x and y are what for you would be X.flatten() and Y.flatten() and the z would be your x.flatten(). This code also works if your data does not come from something square, so if you just want to see what something looks like, if you have a lot of x and y values, and for each one you have a z, this shows you what you want as well.
Note: this is not a 3D plot, but i (personnal opinion) feel that a scatterplot in which the z-dimension is your colorbar seems to show much more what you need to know, compared to a 3D plot that you have to rotate around all the time, to be able to see at the angle that might show you something you want to know
Edit:
for the full code, that you can just copypaste (put this after the first piece in my post)
import numpy
X,Y = meshgrid(gammas, psis)
scatterme(X.flatten(), Y.flatten(), x.flatten())