Plotting 3D distribution in python - python

I would like to plot my data in 3D like this figure(The filled circles are shown in gray scale based on the declination; darker colours mean lower declination.The dots in the R.A.-Dec. plane are the projection on the celestial plane)
I plot like this but I am not able to get like the given figure given above
import numpy as np, math
import matplotlib.pyplot as plt
from astropy.table import Table
from mpl_toolkits.mplot3d import Axes3D
data=Table.read('test_data.fits')
min_red=min(data['redshift'])
fig = plt.figure(figsize=(16,14))
ax = Axes3D(fig)
ax = fig.gca(projection='3d')
ax.view_init(10,30)
ax.plot(data['ra'], data['dec'], data['redshift'],'ko',markersize=5,linewidth=2)
m=ax.plot(data['ra'], data['dec'], 'ro', markersize=1, color='r', zdir='z', zs=min_red)
ax.set_xlabel('ra')
ax.set_ylabel('dec')
ax.set_zlabel('redshift')
plt.show()
But I got like this figure(the dots in Ra and Dec are the projection on the celestial plane)
How to plot like the first figure. Kindly do help

I think the easiest would be to use Axes3D.scatter as following :
import numpy as np, math
import matplotlib.pyplot as plt
from astropy.table import Table
from mpl_toolkits.mplot3d import Axes3D
data=Table.read('test_data.fits')
min_red=min(data['redshift'])
fig = plt.figure(figsize=(16,14))
ax = Axes3D(fig)
ax = fig.gca(projection='3d')
ax.view_init(10,30)
y=list(data['dec'])
ax.scatter(data['ra'], data['dec'], data['redshift'],'ko', c=y, cmap = 'Greys')
m=ax.plot(data['ra'], data['dec'], 'ro', markersize=1, color='r', zdir='z', zs=min_red)
ax.set_xlabel('ra')
ax.set_ylabel('dec')
ax.set_zlabel('redshift')
plt.show()
As specified in Axes3D.scatter documentation :
A color. c can be a single color format string, or a sequence of color specifications of length N, or a sequence of N numbers to be mapped to colors using the cmap and norm specified via kwargs (see below). Note that c should not be a single numeric RGB or RGBA sequence because that is indistinguishable from an array of values to be colormapped. c can be a 2-D array in which the rows are RGB or RGBA, however, including the case of a single row to specify the same color for all points.
My result with the code above

Related

Problems with steep 3d plot in python

I get a really ugly plot using trisurf. I would like that the steep curve connecting the 0 value with the 1 value (z can be only 0 or 1) hadn't the weird orange triangles that appear in my plot:
Without cmap is even worse:
I would be expecting something like this:
but with my range of x,y (they form like a circle, as you can see in the previous plot). How can I do it?
You can download the data used to make the plot here.
My code is really basic:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
N, theta, omega, position, A = np.loadtxt('features.txt', unpack=True)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
my_cmap = plt.get_cmap('hot')
ax.plot_trisurf(theta, omega, A, cmap = my_cmap, antialiased=True)
plt.show()

Show legend that matplotlib dynamically created

My df has 4 columns: x, y, z, and grouping. I have created a 3D plot, with the assigned color of each point being decided by what grouping it belongs to in that row. For reference, a "grouping" can be any number from 1 to 6. The code is shown below:
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter3D(df.x, df.y, df.z, c=df.grouping)
plt.show()
I would like to show a legend on the plot that shows which color belongs to which grouping. Previously, I was using Seaborn for a 2D plot and the legend was automatically plotted. How can I add this feature with matplotlib?
If the values to be colormapped are numeric, the solution can be as simple as:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
a = np.random.rand(3,40)
c = np.random.randint(1,7, size=a.shape[1])
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
sc = ax.scatter3D(*a, c=c)
plt.legend(*sc.legend_elements())
plt.show()

How to make the color of one end of colorbar darker in matplotlib?

Say I have the following plot:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap='Blues', vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
The colorbar has the (almost) white color assigned to the lowest values. How do I make it slightly darker? I want that instead of the colorbar ranging from white to blue, it should range from light blue to dark blue. Like, the color for the value 0 should be something like what it is for the value 0.4 in the plot above.
I found this when searching about it, but the question (and the solutions) is about making all the colors darker, which is not what I am looking for.
Although the suggestion of #user3483203 is very good, you do re-interpolate the colormap. You could avoid this by first getting the colormap as a matrix of colors (based on the original interpolation) and then select a part of this matrix as your new colormap:
import matplotlib as mpl
cmap = mpl.cm.Blues(np.linspace(0,1,20))
cmap = mpl.colors.ListedColormap(cmap[10:,:-1])
Your example then becomes
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
cmap = mpl.cm.Blues(np.linspace(0,1,20))
cmap = mpl.colors.ListedColormap(cmap[10:,:-1])
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap=cmap, vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
which gives
which is in this case probably equivalent to re-interpolated colormap, as Blues itself comes from some interpolation.
For other colormaps the results may be quite different. For example, for jet:
No new interpolation, but just a subset of the original colormap (i.e. current solution):
Using re-interpolation (i.e. #user3483203's solution):
Simply define your own custom colormap:
from matplotlib.colors import LinearSegmentedColormap
colors = [(0.6, 0.76, 0.98), (0, 0.21, 0.46)] # Experiment with this
cm = LinearSegmentedColormap.from_list('test', colors, N=10)
Then just plug it in for the cmap parameter:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap=cm, vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
And the result:
Using set_clim is a simple way to get your colors adjusted the way you probably want:
c.set_clim(-0.5, 1.0)
This sets the color limit (first value is vmin and second is vmax).
↳ https://matplotlib.org/api/_as_gen/matplotlib.pyplot.clim.html

mplot3D fill_between extends over axis limits

I have questions related to creating a simple lineplot in Python with mplot3D where the area under the plot is filled. I am using Python 2.7.5 on RedHatEnterprise 7.2, matplotlib 1.2.0 and numpy 1.7.2.
Using the code below, I am able to generate a line plot. This is displayed as expected with the beginning / end of the plot set by the limits of the imported data set.
I am then trying to fill the area between the line plot and -0.1 using the answer given by Bart from Plotting a series of 2D plots projected in 3D in a perspectival way. This works, however, the filled area is continued beyond the limits of the data set. This is also the case when running the example from the link.
This screen shot shows the plot generated with filled area extending beyond the set axis limits.
How do I achieve that the filled area is only the range of the data set or the axis limits whichever is smaller?
How do I add a legend for those plots onto the figure?
Code as follows:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
x,y = genfromtxt("data.dat",unpack=True)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
ax.plot(x,y,1,zdir="y",label="line plot")
ax.legend()
ax.set_xlim3d(852.353,852.359)
ax.set_zlim3d(-0.1,5)
ax.set_ylim3d(0,2)
ax.get_xaxis().get_major_formatter().set_useOffset(False)
plt.show()
I don't know how to put fill_between working the way you want it to, but I can provide an alternative using a 3D polygon:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection # New import
#x,y = genfromtxt("data.dat",unpack=True)
# Generated some random data
w = 3
x,y = np.arange(100), np.random.randint(0,100+w,100)
y = np.array([y[i-w:i+w].mean() for i in range(3,100+w)])
z = np.zeros(x.shape)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
verts = [(x[i],z[i],y[i]) for i in range(len(x))] + [(x.max(),0,0),(x.min(),0,0)]
ax.add_collection3d(Poly3DCollection([verts],color='orange')) # Add a polygon instead of fill_between
ax.plot(x,z,y,label="line plot")
ax.legend()
ax.set_ylim(-1,1)
plt.show()
The code above generates some random data. Builds vertices from it and plots a polygon with those vertices. This will give you the plot you wish (but does not use fill_between). The result is:

Plot sample with different colors in matplotlib

I tried the following code to plot a set of samples over a 2D plane.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
# some code generating x and y
matplotlib.rcParams['axes.unicode_minus'] = False
fig, ax = plt.subplots()
ax.plot(x, y, 'o')
ax.set_title('Using hypen instead of unicode minus')
plt.show()
I would like to provide a list of values (where each values ranges from 0 to k-1), so that each sample is displayed with the corresponding color. How would I need to modify the code above?

Categories