I am unable to figure out a way to get a legend of my plot. My data is a data frame consisting of 3 columns x, y and z. x and y represent the co-ordinates of a point and z is the label(0,1,2,3) that the point belongs to. Sample data :
I need to plot a scatterplot with a legend containing a colour representing a respective label.
I have plotted the scatterplot but am unable to understand how to put the legend in it.
The code I used till now is(dft is the dataframe) :
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot()
ax.scatter(dft['x'] , dft['y'], c=dft['z'], cmap = 'hsv')
plt.show()
The figure I obtained is :
I need a legend for each color.
You can try this code instead:
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(8,8))
plt.scatter(dft['x'] , dft['y'], c=dft['z'], cmap = 'hsv')
plt.colorbar()
Related
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()
What I want to achieve with Python 3.6 is something like this :
Obviously made in paint and missing some ticks on the xAxis. Is something like this possible? Essentially, can I control exactly where to plot a histogram (and with what orientation)?
I specifically want them to be on the same axes just like the figure above and not on separate axes or subplots.
fig = plt.figure()
ax2Handler = fig.gca()
ax2Handler.scatter(np.array(np.arange(0,len(xData),1)), xData)
ax2Handler.hist(xData,bins=60,orientation='horizontal',normed=True)
This and other approaches (of inverting the axes) gave me no results. xData is loaded from a panda dataframe.
# This also doesn't work as intended
fig = plt.figure()
axHistHandler = fig.gca()
axScatterHandler = fig.gca()
axHistHandler.invert_xaxis()
axHistHandler.hist(xData,orientation='horizontal')
axScatterHandler.scatter(np.array(np.arange(0,len(xData),1)), xData)
A. using two axes
There is simply no reason not to use two different axes. The plot from the question can easily be reproduced with two different axes:
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("ggplot")
xData = np.random.rand(1000)
fig,(ax,ax2)= plt.subplots(ncols=2, sharey=True)
fig.subplots_adjust(wspace=0)
ax2.scatter(np.linspace(0,1,len(xData)), xData, s=9)
ax.hist(xData,bins=60,orientation='horizontal',normed=True)
ax.invert_xaxis()
ax.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.tick_params(axis="y", left=0)
plt.show()
B. using a single axes
Just for the sake of answering the question: In order to plot both in the same axes, one can shift the bars by their length towards the left, effectively giving a mirrored histogram.
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("ggplot")
xData = np.random.rand(1000)
fig,ax= plt.subplots(ncols=1)
fig.subplots_adjust(wspace=0)
ax.scatter(np.linspace(0,1,len(xData)), xData, s=9)
xlim1 = ax.get_xlim()
_,__,bars = ax.hist(xData,bins=60,orientation='horizontal',normed=True)
for bar in bars:
bar.set_x(-bar.get_width())
xlim2 = ax.get_xlim()
ax.set_xlim(-xlim2[1],xlim1[1])
plt.show()
You might be interested in seaborn jointplots:
# Import and fake data
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
data = np.random.randn(2,1000)
# actual plot
jg = sns.jointplot(data[0], data[1], marginal_kws={"bins":100})
jg.ax_marg_x.set_visible(False) # remove the top axis
plt.subplots_adjust(top=1.15) # fill the empty space
produces this:
See more examples of bivariate distribution representations, available in Seaborn.
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:
I'm using matplotlib to produce a 3d trisurf graph. I have everything working except that I would like to invert the y-axis, so that the origin is 0,0 not 0,100. I've looked through the matplotlib axes3d API and cannot figure out how to do this. Here is my code:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
# my data, xs=xaxis, ys=yaxis, zs=zaxis
mortar_xs = []
cycles_ys = []
score_zs = []
#... populate my data for the 3 arrays: mortar_xs, cycles_ys, score_zs
# plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(mortar_xs,cycles_ys,score_zs,cmap=cm.coolwarm)
ax.set_zlim(bottom=0.0,top=1.0)
ax.legend()
ax.set_xlabel("# Mortar")
ax.set_ylabel("# Goals")
ax.set_zlabel("# Score")
plt.show()
My graph produced is the following, but I need the '# Goals' or the y-axis inverted, so that the origin is 0,0 not 0,100. If possible, I would like to do this without changing my data.
tmdavison's comment is what I was looking for:
ax.set_ylim(0,100)
Or
ax.set_ylim(100,0)
The simplest method would be to use ax.invert_yaxis()
I am using scatter plot in matplotlib to plot some points. I have two 1D arrays each storing the x and y coordinate of the samples. Also there is another 1D array that stores the label(to decide in which colour the point should be plotted). I programmed thus far:
import matplotlib.pyplot as plt
X = [1,2,3,4,5,6,7]
Y = [1,2,3,4,5,6,7]
label = [0,1,4,2,3,1,1]
plt.scatter(X, Y, c= label, s=50)
plt.show()
Now I want to be able to see which color corresponds to which label?
I looked up the implementation of legends in matplotlib like the one here:
how to add legend for scatter()?
However they are suggesting to create a plot for each label of sample. However all my labels are in the same 1D array(label). How can I achieve this?
You could do it with a colormap. Some examples of how to do it are here.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as colors
X = [1,2,3,4,5,6,7]
Y = [1,2,3,4,5,6,7]
label = [0,1,4,2,3,1,1]
# Define a colormap with the right number of colors
cmap = plt.cm.get_cmap('jet',max(label)-min(label)+1)
bounds = range(min(label),max(label)+2)
norm = colors.BoundaryNorm(bounds, cmap.N)
plt.scatter(X, Y, c= label, s=50, cmap=cmap, norm=norm)
# Add a colorbar. Move the ticks up by 0.5, so they are centred on the colour.
cb=plt.colorbar(ticks=np.array(label)+0.5)
cb.set_ticklabels(label)
plt.show()
You might need to play around to get the tick labels centred on their colours, but you get the idea.