Related
So I found a custom script to make a waterfall plot from a dataframe, which I customized for my purposes. When I run the function for small number of columns, each layer plots accordingly with the subsequent plot properly placed behind the previous plot. When I keep including a larger number of the columns, it starts plotting subsequent plots over the previous ones.
I tried using PolyCollections, and LineCollections and I can't seem to fix this. Is it a bug? Is there a work-around?
def waterfall(X, numTrials):
# Function to generate formats for facecolors
cc = lambda arg: colorConverter.to_rgba(arg, alpha=1)
# This is just wrong. There must be some way to use the meshgrid or why bother.
verts = []
for i in np.arange(numTrials)+1:
verts.append(list(zip(X['Time'].values, X['Trial #'+str(i)].values)))
xmin = np.floor(np.min(X['Time'].values))
xmax = np.ceil(np.max(X['Time'].values))
ymin = -1
ymax = numTrials+1
zmin = np.floor(np.min(X.drop(columns=['Time']).values))
zmax = np.ceil(np.max(X.drop(columns=['Time']).values))
fig=plt.figure()
fig.set_size_inches(15,10)
ax = Axes3D(fig)
poly = PolyCollection(verts,closed='True',edgecolors=[cc('k')],facecolors=[cc('w')])
ax.add_collection3d(poly, zs=np.arange(numTrials)+1, zdir='y')
ax.set_xlim(xmin,xmax)
ax.set_ylim(ymin,ymax)
ax.set_zlim(zmin,zmax)
ax.view_init(25, -110)
plt.show()
for x in np.arange(5,100,20):
waterfall(CRresponse, x)
This is an example of a proper output, for low number of columns:
enter image description here
This is an example of a messed up output for higher number of columns:
enter image description here
Thank you for any help on the matter, and I appreciate your patience for a first time poster
I have attached 2 images. I am trying to replot image 1. I am using the same data which has been used to plot that image. I need to know how we can scale the y-axis of my plot.
my code:
a = pd.read_csv('SED.csv')
a.plot(kind = 'scatter', x = 'Frequency', y = 'Flux Density')
plt.xlim(1E+7,1E+8)
plt.ylim(1E-3,1E+4)
plt.show()
I need a scaled graph like this
This what I am trying to do with python
Try to change yscale to log
plt.xlim(1E+8, 1E+24)
plt.ylim(1E-12,1E+3)
plt.yscale("log")
plt.xscale("log")
I want to have the y axis on the right hand side of my plot, but also have the label facing the correct direction. There's many answers that explain the first part, which can be done as follows:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot()
ax.plot([1,2,3,4,5])
ax.set_ylabel("RHS")
ax.yaxis.set_label_position("right")
ax.yaxis.tick_right()
plt.show()
Which produces the following:
But the issue here is the yaxis label on the right hand side is facing outwards, and ideally I would like it to face inwards, something like the following:
Any help with this would be much appreciated!
Just add the following kwargs to your set_ylabel call:
ax.set_ylabel("RHS",rotation=-90,labelpad=15)
which gives the intended output:
If you want to modify label after it has been set, alternatively you can do something like:
yl = ax.set_ylabel("RHS")
ax.yaxis.set_label_position("right")
yl.set_rotation(50)
# do some other stuff
then don't forget to call plt.draw() to make it effective. You may want to have a look at matplotlib text instance properties.
So I have a plot with a basemap, a colormesh on top, and a colorbar set to cbar. I want the colorbar orientation to be horizontal instead of vertical, but when I set orientation='horizontal' in the cbar=m.colorbar line after extend='max', I get the following error: "colorbar() got multiple values for keyword argument 'orientation'"
Someone on another question explained why this happens, but I honestly couldn't understand the answer or see an explanation of how to fix it. Can someone help? I tried using plt.colorbar instead, but for some reason that doesn't accept my tick settings.
Here's what my plot looked like before...
#Set cmap properties
bounds = np.array([0.1,0.2,0.5,1,2,3,4,6,9,13,20,30])
norm = colors.LogNorm(vmin=0.1,vmax=30) #creates logarithmic scale
#Create basemap
fig = plt.figure(figsize=(15.,10.))
m = Basemap(projection='cyl',llcrnrlat=-90,urcrnrlat=90,llcrnrlon=0,urcrnrlon=360.,lon_0=180.,resolution='c')
m.drawcoastlines(linewidth=1)
m.drawcountries(linewidth=1)
m.drawparallels(np.arange(-90,90,30.),linewidth=0.3)
m.drawmeridians(np.arange(-180.,180.,90.),linewidth=0.3)
meshlon,meshlat = np.meshgrid(lon,lat)
x,y = m(meshlon,meshlat)
#Plot variables
trend = m.pcolormesh(x,y,lintrends_36,cmap='jet', norm=norm, shading='gouraud')
#Set plot properties
plt.tight_layout()
#Colorbar
cbar=m.colorbar(trend, size='3%',ticks=bounds,extend="max") #THIS LINE
cbar.set_label(label='Linear Trend (mm/day/decade)',size=30)
cbar.set_ticklabels(bounds)
#Titles & labels
plt.suptitle('Linear Trends of Precipitation (CanESM2)',fontsize=40,y=0.962)
plt.title('a) 1979-2014',fontsize=40)
plt.ylabel('Latitude',fontsize=30)
plt.show()
When orientation is attempted (all other code being the same)...
And the map looks like this.
You need to use location="bottom"
cbar=m.colorbar(trend, size='3%',ticks=bounds,extend="max",location="bottom")
I got that from this example in the basemap documentation.
As others have already stated in the comments
plt.colorbar(orientation='horizontal')
is an alternative (simpler) solution!
I have a small issue with matplotlib.pyplot and I hope someone might have come across it before.
I have data that contain X,Y,e values that are the X, Y measurements of a variable and e are the errors of the measurements in Y. I need to plot them in a log log scale.
I use the plt.errorbars function to plot them and then set yscale and xscale to log and this works fine. But I need to also plot a line on the same graph that needs to be in linear scale.
I am able to have the plots done separately just fine but I would like to have them in the same image if possible. Do you have any ideas? I am posting what I have done for now.
Cheers,
Kimon
tdlist = np.array([0.01,0.02,0.05,0.1,0.2,0.3,0.4,0.5,0.8,1,2,5,10,15,20,25,30,40,60,80,100,150,200,250,300,400])
freqlist=np.array([30,40,50,60,70,80,90,100,110,120,140,160,180,200,220,250,300,350,400,450])
filename=opts.filename
data = reader(filename)
data2 = logconv(data)
#x,y,e the data. Calculating usefull sums
x = data2[0]
y = data2[1]
e = data2[2]
xoe2 = np.sum(x/e**2)
yoe2 = np.sum(y/e**2)
xyoe2 = np.sum(x*y/e**2)
oe2 = np.sum(1/e**2)
x2oe2 = np.sum(x**2/e**2)
aslope = (xoe2*yoe2-xyoe2*oe2)/(xoe2**2-x2oe2*oe2)
binter = (xyoe2-aslope*x2oe2)/xoe2
aerr = np.sqrt(oe2/(x2oe2*oe2-xoe2**2))
berr = np.sqrt(x2oe2/(x2oe2*oe2-xoe2**2))
print('slope is ',aslope,' +- ', aerr)
print('inter is ',binter,' +- ', berr)
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax2 = fig.add_axes(ax1.get_position(), frameon=False)
ax1.errorbar(data[0],data[1],yerr=data[2],fmt='o')
ax1.set_xscale('log',basex=10)
ax1.set_yscale('log',basey=10)
ax1.set_yticks([])
ax1.set_xticks([])
ax2.plot(x,aslope*x+binter,'r')
ax2.plot(x,(aslope-aerr)*x+(binter+berr),'--')
ax2.plot(x,(aslope+aerr)*x+(binter-berr),'--')
ax2.set_xscale('linear')
ax2.set_yscale('linear')
plt.xticks(np.log10(freqlist),freqlist.astype('int'))
plt.yticks(np.log10(tdlist),tdlist.astype('float'))
plt.xlabel('Frequency (MHz)')
plt.ylabel('t_s (msec)')
fitndx1 = 'Fit slope '+"{0:.2f}".format(aslope)+u"\u00B1"+"{0:.2f}".format(aerr)
plt.legend(('Data',fitndx1))
plt.show()
Following Molly's suggestion I managed to get closer to my goal but still not there. I am adding a bit more info for what I am trying to do and it might clarify things a bit.
I am setting ax1 to the errobar plot that uses loglog scale. I need to use errorbar and not loglog plot so that I can display the errors with my points.
I am using ax2 to plot the linear fit in linealinear scale.
Moreover I do not want the x and y axes to display values that are 10,100,1000 powers of ten but my own axes labels that have the spacing I want therefore I am using the plt.xticks. I tried ax1.set_yticks and ax1.set_yticklabes but with no success. Below is the image I am getting.
I do not have enough reputation to post an image but here is the link of it uploaded
http://postimg.org/image/uojanigab/
The values of my points should be x range = 40 - 80 and y range = 5 -200 as the fit lines are now.
You can create two overlapping axes using the add_suplot method of figure. Here's an example:
from matplotlib import pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax2 = fig.add_axes(ax1.get_position(), frameon=False)
ax1.loglog([1,10,100,1000],[1000,1,100,10])
ax2.plot([5,10,11,13],'r')
plt.show()
You can then turn off the x and y ticks for the linear scale plot like this:
ax2.set_xticks([])
ax2.set_yticks([])
I was not able to get two sets of axis working with the errorbar function so I had to convert everything to log scale including my linear plot. Below is the code I use to get it might be useful to someone.
plt.errorbar(data[0],data[1],yerr=data[2],fmt='o')
plt.xscale('log',basex=10)
plt.yscale('log',basey=10)
plt.plot(data[0],data[0]**aslope*10**binter,'r')
plt.plot(data[0],data[0]**(aslope-aerr)*10**(binter+berr),'--')
plt.plot(data[0],data[0]**(aslope+aerr)*10**(binter-berr),'--')
plt.xticks(freqlist,freqlist.astype('int'))
plt.yticks(tdlist,tdlist.astype('float'))
plt.xlabel('Frequency (MHz)')
plt.ylabel('t_s (msec)')
fitndx1 = 'Fit slope '+"{0:.2f}".format(aslope)+u"\u00B1"+"{0:.2f}".format(aerr)
plt.legend(('Data',fitndx1))
plt.show()
And here is the link to the final image
http://postimg.org/image/bevj2k6nf/