How to project 2d plots (e.g. boxplot) to 3d in matplotlib? - python

I have found code to project 2d bar plots or scatter plots into 3d. For example, with the following code:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111, projection='3d')
nbins = 50
for i, c, z in zip([0,1,2],['r', 'g', 'b', 'y'], [30, 20, 10, 0]):
ys = np.random.normal(loc=10, scale=10, size=2000)
hist, bins = np.histogram(ys, bins=nbins)
xs = (bins[:-1] + bins[1:])/2
ax.bar(xs, hist,zs=z, zdir='y', color=c, ec=c, alpha=0.8)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
However, I want to project other 2d plots into 3d, for example, boxplot. When I modified the code above to boxplot, I cannot use arguments including "zs=z" and "zdir='y'" to set apart 2d plots at different positions. What should I do to make boxplots into figure above? Thanks!

Related

How to use np.arange() to create a 3D scatter plot

I'm trying to recreate a 3D scatter plot figure but I'm having a hard time with getting the range right on the y axis.
This is the figure that I am trying to emulate:
Here's my code for the np.arange():
from mpl_toolkits import mplot3d
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=[15,15])
z = 520 * np.random.random(100)
x = np.arange(0,20,0.2)
y = np.arange(0,20,0.2)
ax3 = fig.add_subplot(2,2,3, projection='3d')
ax3.set_xlabel('x', c='r', size=14)
ax3.set_ylabel('y', c='r', size=14)
ax3.set_zlabel('z', c='r', size=14)
ax3.scatter3D(x,y,z, c=z, cmap='jet')
ax3.view_init(25,45);
This is the output:
I'm not trying to make it look exactly the same with the angle but I need to get the axis plots correct.

How to plot a density bar next to my density scatter plot? [duplicate]

I'm working with data that has the data has 3 plotting parameters: x,y,c. How do you create a custom color value for a scatter plot?
Extending this example I'm trying to do:
import matplotlib
import matplotlib.pyplot as plt
cm = matplotlib.cm.get_cmap('RdYlBu')
colors=[cm(1.*i/20) for i in range(20)]
xy = range(20)
plt.subplot(111)
colorlist=[colors[x/2] for x in xy] #actually some other non-linear relationship
plt.scatter(xy, xy, c=colorlist, s=35, vmin=0, vmax=20)
plt.colorbar()
plt.show()
but the result is TypeError: You must first set_array for mappable
From the matplotlib docs on scatter 1:
cmap is only used if c is an array of floats
So colorlist needs to be a list of floats rather than a list of tuples as you have it now.
plt.colorbar() wants a mappable object, like the CircleCollection that plt.scatter() returns.
vmin and vmax can then control the limits of your colorbar. Things outside vmin/vmax get the colors of the endpoints.
How does this work for you?
import matplotlib.pyplot as plt
cm = plt.cm.get_cmap('RdYlBu')
xy = range(20)
z = xy
sc = plt.scatter(xy, xy, c=z, vmin=0, vmax=20, s=35, cmap=cm)
plt.colorbar(sc)
plt.show()
Here is the OOP way of adding a colorbar:
fig, ax = plt.subplots()
im = ax.scatter(x, y, c=c)
fig.colorbar(im, ax=ax)
If you're looking to scatter by two variables and color by the third, Altair can be a great choice.
Creating the dataset
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame(40*np.random.randn(10, 3), columns=['A', 'B','C'])
Altair plot
from altair import *
Chart(df).mark_circle().encode(x='A',y='B', color='C').configure_cell(width=200, height=150)
Plot

Plotting some third variable against x and y in matplotlib scatter?

I'm fairly new to scatter plots and python in general. I am trying to plot a third variable against an x and a y, however, I'm not quite sure how to about specifying that argument? So I would have X values which are ints, y values which are also ints and then on the graph itself I want the model scores to show. Is there any way to do this sort of thing?
Thank you.
You can use color to plot a third value. Here is a very minimal example :
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)
plt.scatter(x,y, c=z, s=5, cmap=cm.hsv)
cbar= plt.colorbar()
plt.show()
Edit
You could also use the size of markers, their transparency, hue or rgb values to depict even more information. Here is an example with marker size, alpha level and color on a perceptually uniform colormap.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as colors
import matplotlib.cm as cmx
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)
t = np.random.rand(100)
w = np.random.rand(100)
fig, ax = plt.subplots(1, 1)
cmap = plt.get_cmap('plasma')
cNorm = colors.Normalize(vmin=0, vmax=max(z))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cmap)
for i in range(100):
ax.scatter(x[i],y[i], c=scalarMap.to_rgba(z[i]), s=t[i]*100, cmap=cmx.plasma, alpha=w[i], edgecolor='none')
scalarMap.set_array([])
fig.colorbar(scalarMap,ax=ax)
for a in [0.1, 0.5, 0.9]:
ax.scatter([], [], c='k', alpha=0.5, s=a*100, label=str(a), edgecolors='none')
l1 = ax.legend(scatterpoints=1, frameon=True, loc='lower left' ,markerscale=1)
for b in [0.25, 0.5, 0.75]:
ax.scatter([], [], c='k', alpha=b, s=50, label=str(b), edgecolors='none')
ax.legend(scatterpoints=1, frameon=True, loc='lower right' ,markerscale=1)
fig.show()
At face value, that question doesn't really make sense because a conventional scatterplot has only two axes, and of course you can't plot points with three dimensions (x, y and accuracy).
However, there are alternative ways to do so.
Use colours
import numpy as np
from matplotlib import pyplot as plt
x = np.random.rand(200)
y = np.random.rand(200)
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x, y, c=(x + y), cmap='RdPu')
scatter takes a c argument, which can be a numeric value, as well as a cmap argument, which can be a string referencing a colormap.
The colormap object translates the numbers provided in c into points along a colour mapping, which you can think of as a gradient bar.
Use 3D axes
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(5, 5))
ax = Axes3D(fig)
ax.scatter(x, y, (x + y))
This turns your 3rd dimension, accuracy, into an ordinary spatial dimension.
Use size of the markers
Very similar to the color option in the first part, you can change the size of the scatter markers (given you have some idea about the scale of the values). So based on the first example, you can also do;
import numpy as np
from matplotlib import pyplot as plt
x = np.random.rand(200)
y = np.random.rand(200)
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x, y, c='k', s=5*(x + y), cmap='RdPu')
scatter takes also the s argument, that changes the size of the markers.

Python matplotlib 3D bar plot with error bars

I am trying to get a 3D barplot with error bars.
I am open to use matplotlib, seaborn or any other python library or tool
Searching in SO I found 3D bar graphs can be done by drawing several 2D plots (here for example). This is my code:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
dades01 = [54,43,24,104,32,63,57,14,32,12]
dades02 = [35,23,14,54,24,33,43,55,23,11]
dades03 = [12,65,24,32,13,54,23,32,12,43]
df_3d = pd.DataFrame([dades01, dades02, dades03]).transpose()
colors = ['r','b','g','y','b','p']
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
z= list(df_3d)
for n, i in enumerate(df_3d):
print 'n',n
xs = np.arange(len(df_3d[i]))
ys = [i for i in df_3d[i]]
zs = z[n]
cs = colors[n]
print ' xs:', xs,'ys:', ys, 'zs',zs, ' cs: ',cs
ax.bar(xs, ys, zs, zdir='y', color=cs, alpha=0.8)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
I get the 3D 'ish' plot.
My question is: How do I add error bars?
To make it easy, lets try to add the same error bars to all the plots:
yerr=[10,10,10,10,10,10,10,10,10,10]
If I add my error bars in each '2D' plot:
ax.bar(xs, ys, zs, zdir='y', color=cs,yerr=[10,10,10,10,10,10,10,10,10,10], alpha=0.8)
Doesn't work:
AttributeError: 'LineCollection' object has no attribute 'do_3d_projection'
I have also tried to add:
#ax.errorbar(xs, ys, zs, yerr=[10,10,10,10,10,10,10,10,10,10], ls = 'none')
But again an error:
TypeError: errorbar() got multiple values for keyword argument 'yerr'
Any idea how I could get 3D plot bars with error bars?
There is no direct way to the best of my knowledge to do it in 3d. However, you can create a workaround solution as shown below. The solution is inspired from here. The trick here is to pass two points lying vertically and then use _ as the marker to act as the error bar cap.
yerr=np.array([10,10,10,10,10,10,10,10,10,10])
for n, i in enumerate(df_3d):
xs = np.arange(len(df_3d[i]))
ys = [i for i in df_3d[i]]
zs = z[n]
cs = colors[n]
ax.bar(xs, ys, zs, zdir='y', color=cs, alpha=0.8)
for i, j in enumerate(ys):
ax.plot([xs[i], xs[i]], [zs, zs], [j+yerr[i], j-yerr[i]], marker="_", color=cs)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
First of all, don't use a 3D plot when a 2D plot would suffice, which in this case, it would. Using 3D plots for 2D data unnecessarily obfuscates things.
Second, you can use a combination of a MultiIndex pandas dataframe to get your desired result:
df = pd.DataFrame({
'a': list(range(5))*3,
'b': [1, 2, 3]*5,
'c': np.random.randint(low=0, high=10, size=15)
}).set_index(['a', 'b'])
fig, ax = plt.subplots(figsize=(10,6))
y_errs = np.random.random(size=(3, 5))
df.unstack().plot.bar(ax=ax, yerr=y_errs)
This produces a plot like the following:
I'm using the 'bmh' style here (i.e., I called plt.style.use('bmh') earlier in my notebook that I had opened), which is why it looks the way it does.

Matplotlib 3D scatter plot with color gradient

How can I create a 3D plot with a color gradient for the points? See the example below, which works for a 2D scatter plot.
Edit (thanks to Chris): What I'm expecting to see from the 3D plot is a color gradient of the points ranging from red to green as in the 2D scatter plot.
What I see in the 3D scatter plot are only red points.
Solution: for some reasons (related to the gradient example I copied elsewhere) I set xrange to len-1, which messes everything in the 3D plot.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Create Map
cm = plt.get_cmap("RdYlGn")
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)
#col = [cm(float(i)/(29)) for i in xrange(29)] # BAD!!!
col = [cm(float(i)/(30)) for i in xrange(30)]
# 2D Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x, y, s=10, c=col, marker='o')
# 3D Plot
fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
ax3D.scatter(x, y, z, s=10, c=col, marker='o')
plt.show()
Here is an example for 3d scatter with gradient colors:
import matplotlib.cm as cmx
from mpl_toolkits.mplot3d import Axes3D
def scatter3d(x,y,z, cs, colorsMap='jet'):
cm = plt.get_cmap(colorsMap)
cNorm = matplotlib.colors.Normalize(vmin=min(cs), vmax=max(cs))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x, y, z, c=scalarMap.to_rgba(cs))
scalarMap.set_array(cs)
fig.colorbar(scalarMap)
plt.show()
Of course, you can choose the scale to range between different values, like 0 and 1.
Following works: I can't figure out why yours doesn't. You should be able to set color as a sequence of RGBA floats, or just sequence of floats.
# Create Map
cm = plt.get_cmap("RdYlGn")
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)
col = np.arange(30)
# 2D Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x, y, s=10, c=col, marker='o')
# 3D Plot
fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
p3d = ax3D.scatter(x, y, z, s=30, c=col, marker='o')
plt.show()
However, in help of scatter, I see the following, it may be related.
A :class:`matplotlib.colors.Colormap` instance or registered
name. If *None*, defaults to rc ``image.cmap``. *cmap* is
only used if *c* is an array of floats.

Categories