I'm trying to plot a contourf-plot using matplotlib (and numpy of course). And it works, it plots what it should plot, but unfortunatelly I cannot set the colorbar range. The problem is that I have a plenty of plots and need all of them to have the same colorbar (same min and max, same colors). I copy&past-ed almost every code snippet I found on the internet, but without success. My code so far:
import numpy as np;
import matplotlib as mpl;
import matplotlib.pyplot as plt;
[...]
plotFreq, plotCoord = np.meshgrid(plotFreqVect, plotCoordVect);
figHandler = plt.figure();
cont_PSD = plt.contourf(plotFreq, plotCoord, plotPxx, 200, linestyle=None);
normi = mpl.colors.Normalize(vmin=-80, vmax=20);
colbar_PSD = plt.colorbar(cont_PSD);
colbar_PSD.set_norm(normi);
#colbar_PSD.norm = normi;
#mpl.colors.Normalize(vmin=-80, vmax=20);
plt.axis([1, 1000, -400, 400]);
As you can see there are three different lines for the colorbar norm, none of them is working. The range is still set automatically...
I mean everything else is working, why not the colorbar? I don't even get errors or warnings.
Thanks,
itpdg
EDIT 1: Pictures, with plt.clim(-80,20):
Please user the levels parameter, a set of examples:
In [9]:
ndom
z = np.random.random((10,10))
Without levels, colorbar will be auto-scaled
In [11]:
plt.contourf(z)
plt.colorbar()
Out[11]:
<matplotlib.colorbar.Colorbar at 0x120d47390>
In [12]:
plt.contourf(z*2)
plt.colorbar()
Out[12]:
<matplotlib.colorbar.Colorbar at 0x120f6ac10>
Control colorbar with explicit levels
In [13]:
plt.contourf(z*2, levels=np.linspace(0,2,20))
plt.colorbar()
Out[13]:
<matplotlib.colorbar.Colorbar at 0x121b119d0>
In [14]:
plt.contourf(z, levels=np.linspace(0,2,20))
plt.colorbar()
Out[14]:
<matplotlib.colorbar.Colorbar at 0x120dc3510>
I ran into this issue a while back and thought it was a bug (see MPL issue #5055). It's not, but it does require using the extend kwarg, which was non-intuitive to me. Here's what you want to do:
normi = mpl.colors.Normalize(vmin=-80, vmax=20)
cont_PSD = plt.contourf(plotFreq, plotCoord, plotPxx,
np.linspace(-80, 20, 200),
linestyle=None,
norm=normi, extend='both')
plt.colorbar(colbar_PSD)
You can do-away with the plt.clim, colbar_PSD.set_norm and other similar calls.
More examples uses of extend= are available here.
Note that this will create a colorbar with 'triangles' at the top and bottom indicating that the data extends beyond the colorbar, but I think you'll like them once you get used to them, they are descriptive.
Good luck!
add this after plt.colorbar():
plt.clim(minimal_value, maximal_value)
for the contour plot, add the args vmin and vmax:
cont_PSD = plt.contourf(plotFreq, plotCoord, plotPxx, 200, linestyle=None,vmin=minimal_value,vmax=maximal_value)
You complete code should work like this :
import numpy as np;
import matplotlib as mpl;
import matplotlib.pyplot as plt;
[...]
plotFreq, plotCoord = np.meshgrid(plotFreqVect, plotCoordVect);
figHandler = plt.figure();
cont_PSD = plt.contourf(plotFreq, plotCoord, plotPxx, 200, linestyle=None,vmin=minimal_value,vmax=maximal_value);
plt.colorbar()
plt.clim(minimal_value,maximal_value)
plt.show()
Related
So am trying to make some plots and was trying to use the cmap "jet". It kept appearing as viridis, so I dug around SE and tried some very simple plots:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 100)
y = x
t = x
df = pd.DataFrame([x,y]).T
df.plot(kind="scatter", x=0, y=1, c=t, cmap="jet")
x = np.arange(0, 100.1)
y = x
t = x
df = pd.DataFrame([x,y]).T
df.plot(kind="scatter", x=0, y=1, c=t, cmap="jet")
Any thoughts on what is going on here? I can tell that it has something to do with the dtype of the fields in the dataframe (added dypte="float" to the first set of code and got the same result as in the second set of code), but don't see why this would be the case.
Naturally, what I really would like is a workaround if there isn't something wrong with my code.
It actually seems to be related to pandas (scatter) plot and as you've pointed out to dtype float - some more details at the end.
A workaround is to use matplotlib.
The plot is looking the same in the end, but the cmap="jet" setting is also applied for float dtype:
Code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
x = np.arange(0, 100.1)
y = x
t = x
df = pd.DataFrame([x,y]).T
fig, ax = plt.subplots(1,1)
sc_plot = ax.scatter(df[0], df[1], c=t, cmap="jet")
fig.colorbar(sc_plot)
ax.set_ylabel('1')
ax.set_xlabel('0')
plt.show()
Or the shorter version (a little bit closer to the brief df.plot call) using pyplot instead of the Object Oriented Interface:
df = pd.DataFrame([x,y]).T
sc_plot = plt.scatter(df[0], df[1], c=t, cmap="jet")
plt.colorbar(sc_plot)
plt.ylabel('1')
plt.xlabel('0')
plt.show()
Concerning the root cause why pandas df.plot isn't following the cmap setting:
The closest I could find is that pandas scatter plot c takes
str, int or array-like
(while I'm not sure why t isn't referring to the index which would be int again).
Even df.plot(kind="scatter", x=0, y=1, c=df.index.values.tolist(), cmap='jet') falls back to viridis, while df.index.values.tolist() clearly is just int.
Which is even more strange, as pandas df.plot also uses matplotlib by default:
Uses the backend specified by the option plotting.backend. By default,
matplotlib is used.
Looks like it's a new bug in pandas 1.5.0. Reverting pandas to 1.4.4 fixes it. So if you don't need 1.5.0 per se, I'd suggest to reinstall 1.4.4 until the bugfix.
Good morning!
I'm making some bar plots with Seaborn, but I've difficulties getting a proper ylabel for them.
Here is a reproductible example:
import pandas as pd
import os
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib
from pdb import set_trace as bp
name = 'test.pdf'
data = pd.DataFrame({'Labels': ['Label', 'Longer label', 'A really really large label'], 'values': [200, 100, 300]})
sns.set_style("dark")
ax = sns.barplot(y = data['Labels'], x = data['values'], data = data)
ax.set(ylabel = 'Labels', xlabel = 'Values')
plt.savefig(name)
plt.close()
As you can see, second and third labels ('Longer label' and 'A really really large label') can't be shown completely and I can't solve it.
Furthermore, I would want to know how to delete these short black lines at top and at left of the image.
Thanks you very much!!
You need to specify bbox_inches='tight' while saving the figure as
plt.savefig(name, bbox_inches='tight')
If you are working with JuPyter notebooks, then plt.tight_layout() would work for inline plots as commented above by #ALollZ
I'm having trouble replicating an old colormap I've used in matplotlib. It seems as if it was the default colormap because in the original code, no colormap was specified.
So looking at the old figure I made I've measured the colours from the colorbar using gpick. I've inputted these into a custom colormap as follows:
blue_red1 = LinearSegmentedColormap.from_list('mycmap', [
(0, '#6666de'),
(0.1428, '#668cff'),
(0.2856, '#66d9ff'),
(0.4284, '#92ffce'),
(0.5712, '#d0ff90'),
(0.714, '#ffe366'),
(0.8568, '#ff9b66'),
(1, '#db6666')])
CS = plt.contourf(H, temps, diff_list, cmap=blue_red1)
plt.savefig('out.png')
Yet when I measure the output colours with gpick again they have different hex values (and I can tell they're different).
What could be causing this?
The original I'm trying to replicate, and the output from the custom colour map are linked below:
You may get much closer to the desired result using the following.
The logic is that each color in the colorbar is the value corresponding to the mean of its interval.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
X,Y=np.meshgrid(np.linspace(0,1),np.linspace(0,1) )
Z = X+Y
blue_red1 = LinearSegmentedColormap.from_list('mycmap', [
(0.0000, '#6666de'),
(0.0625, '#6666de'),
(0.1875, '#668cff'),
(0.3125, '#66d9ff'),
(0.4375, '#92ffce'),
(0.5625, '#d0ff90'),
(0.6875, '#ffe366'),
(0.8125, '#ff9b66'),
(0.9375, '#db6666'),
(1.0000, '#db6666')])
CS = plt.contourf(X,Y,Z, cmap=blue_red1)
plt.colorbar()
plt.show()
The other option is to use a ListedColormap. This gives the accurate colors.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
X,Y=np.meshgrid(np.linspace(0,1),np.linspace(0,1) )
Z = X+Y
blue_red1 = ListedColormap(['#6666de','#668cff','#66d9ff','#92ffce','#d0ff90',
'#ffe366','#ff9b66','#db6666'],'mycmap')
CS = plt.contourf(X,Y,Z, cmap=blue_red1)
plt.colorbar()
plt.show()
I have a set of points [index, minimum] and I would like to scatter one point i (index[i],minimum[i]) at a time so that I can see the evolution of the plot.
I would like to know how I can do that. I have tried a time- delay like:
plt.figure()
for i in range (np.size(index)):
plt.plot(index[i], minimum[i],'*')
plt.show()
time.sleep(1)
it did not work.
Thanks in advance.
Might seem stupid but did you import the time library ? Also there is no indentation, is your code really like that or that's a copy/paste fail ?
Edit: Answer in comments, use plt.pause(1), see http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.pause
you should use an "animate" plot :
http://matplotlib.org/api/animation_api.html
and here some good example :
http://matplotlib.org/examples/animation/index.html
You do have to use a nan arrays to plot empty values then update your array as you move in time. Here is a working example:
import numpy as np
import matplotlib.pyplot as plt
import time
nbPoints = 100
nanArray = np.array(np.ones(nbPoints))
nanArray[:] = np.nan
index = range(nbPoints)
minimum = np.random.randint(5, size=nbPoints)
minimumPlotData = nanArray
fig = plt.figure()
ax = plt.subplot(111)
ax.set_xlim(0, nbPoints)
ax.set_ylim(min(minimum), max(minimum))
li, = ax.plot(index,minimumPlotData, marker = 'o', linestyle="")
fig.canvas.draw()
plt.show(block=False)
for i in range(nbPoints):
minimumPlotData[i]=minimum[i]
li.set_ydata(minimumPlotData)
fig.canvas.draw()
time.sleep(1)
I am trying to do an errorplot with different marker-colors in python 2.7. Additionally I am including to line plots.
I found a way here: matplotlib errorbar plot - using a custom colormap using a scatter plot for the colors and errorbar() for the bars.
As you can see in my example code, in the legend I always get one entry too much (just at the top). I cannot figure out, why. Tried to exclude it, which did not work. Did not find something helpful either, as I cannot really call the first legend entry.
Any ideas?
Here's my code:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
data = pd.DataFrame()
data['x'] = range(10)
data['y'] = data.x
data['err'] = .5
data['col'] = np.where(data.y<5,'r','b')
### setup 1-1 line
lin = pd.DataFrame() # setting 1-1 line
lin['x'] = range(10)
lin['y'] = range(10)
### setup 1-2 line
lin['x2'] = lin.x
lin['y2'] = lin.y
plt.errorbar(data.x, data.y, yerr = data.err, \
xerr = .3, fmt=' ', markersize=4, zorder = 1)
plt.scatter(data.x,data.y, marker='o', color = data.col, zorder = 2)
plt.plot(lin.x,lin.y,'g-')
plt.plot(lin.x2,1.8*lin.y2,'r-')
plt.legend(['','1-1 line', '1-1.8 line','holla','molla'], loc=4)
What I get is:
Thanks for your help!
To clean this whole thing up, I post a proper answer instead of comments.
The problem could be solved by upgrading matplotlib from 1.3.1 to 1.5.1. Easy as that.