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.
Related
I'm currently trying to make a nested doughnut chart with four layers and I have come across some problems with it.
There is one dependency in my data. I look into the changes done with a specific method and divide them into agronomical and academic traits. I then create a fourth ring which shows basically the amount of academic and each agronomical trait. I don't know how to automatically align both doughnut rings so they match.
I looked into the matplotlib documentation, but I don't understand the addressing of the colormaps. I took over the example code, but in the end its not really understandable how this is addressing the colors of it.
I need to make a legend for the chart. However, due to the long names of some of the subgroups, I can not show them in the pie chart but they should appear in the legend. When I draw the legend via the ax.legend function, it adds only the groups to the legend which I addressed in the ax.pie function with labels=, if I use fig.legend for drawing the legend, the colors are not matching at all. I tried to use the handles= function I stumbled across some posts here on StackOverflow. But they just give me an error
AttributeError: 'tuple' object has no attribute 'legend'
I would like to add the pct and number of occurrences to my legend, but I guess there is no "easy" way for that?
´´´
import numpy as np
import pandas
import pandas as pd
import matplotlib.pyplot as plt
import openpyxl
df = pandas.read_excel("savedrecs.xlsx", sheet_name="test")
#print(df.head())
size = 0.3
fig, ax = plt.subplots(figsize=(12,8))
#Colors----
cmap1 = plt.get_cmap("tab20c")
cmap2 = plt.get_cmap("tab10")
outer_colors = cmap1(np.arange(20))
inner_colors = cmap1(np.arange(12))
sr_colors = cmap1(np.arange(5,6))
#Data----
third_ring = df[df["Group"].str.contains("group")]
fourth_ring = df[df["Group"].str.contains("Target trait")]
second_ring = df[df["Group"].str.contains("Cultivar")]
first_ring = df[df["Group"].str.contains("Mutation")]
#----
#---Testautopct---
def make_autopct(values):
def my_autopct(pct):
total = sum(values)
val = int(round(pct*total/100.0))
return '{p:.2f}%\n({v:d})'.format(p=pct,v=val)
return my_autopct
#-----
#Piechart----
ir = ax.pie(first_ring["Occurence"], radius=1-size, labels=first_ring["Name"], textprops={"fontsize":8},labeldistance=0,
colors=sr_colors, wedgeprops=dict(edgecolor="w"))
sr = ax.pie(second_ring["Occurence"],
autopct=make_autopct(second_ring["Occurence"]),pctdistance=0.83,textprops={"fontsize":8},
radius=1,wedgeprops=dict(width=size, edgecolor="w"),startangle=90,colors=inner_colors)
tr = ax.pie(third_ring["Occurence"],
autopct=make_autopct(third_ring["Occurence"]),labels=third_ring["Name"],pctdistance=0.83,textprops={"fontsize":8},
radius=1+size,wedgeprops=dict(width=size, edgecolor="w"),startangle=90,colors=outer_colors)
fr = ax.pie(fourth_ring["Occurence"],
autopct=make_autopct(fourth_ring["Occurence"]),labels=fourth_ring["Name"],pctdistance=0.83,textprops={"fontsize":8},
radius=1+size*2,wedgeprops=dict(width=size, edgecolor="w"),startangle=90,colors=outer_colors)
#---Legend & Title----
ax.legend( bbox_to_anchor=(1.04, 0.5), loc="center left", borderaxespad=10 ,fancybox=True, shadow=False, ncol=1, title="This will be a fancy legend title")
fig.suptitle("This will be a fancy title, which I don't know yet!")
#----
plt.tight_layout()
plt.show()
´´´
The output of this code is then as follows:
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
so I am plotting error bar of pandas dataframe. Now the error bar has a weird arrow at the top, but what I want is a horizontal line. For example, a figure like this:
But now my error bar ends with arrow instead of a horinzontal line.
Here is the code i used to generate it:
plot = meansum.plot(
kind="bar",
yerr=stdsum,
colormap="OrRd_r",
edgecolor="black",
grid=False,
figsize=(8, 2),
ax=ax,
position=0.45,
error_kw=dict(ecolor="black", elinewidth=0.5, lolims=True, marker="o"),
width=0.8,
)
So what should I change to make the error become the one I want. Thx.
Using plt.errorbar from matplotlib makes it easier as it returns several objects including the caplines which contain the marker you want to change (the arrow which is automatically used when lolims is set to True, see docs).
Using pandas, you just need to dig the correct line in the children of plot and change its marker:
import pandas as pd
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
df = pd.DataFrame({"val":[1,2,3,4],"error":[.4,.3,.6,.9]})
meansum = df["val"]
stdsum = df["error"]
plot = meansum.plot(kind='bar',yerr=stdsum,colormap='OrRd_r',edgecolor='black',grid=False,figsize=8,2),ax=ax,position=0.45,error_kw=dict(ecolor='black',elinewidth=0.5, lolims=True),width=0.8)
for ch in plot.get_children():
if str(ch).startswith('Line2D'): # this is silly, but it appears that the first Line in the children are the caplines...
ch.set_marker('_')
ch.set_markersize(10) # to change its size
break
plt.show()
The result looks like:
Just don't set lolim = True and you are good to go, an example with sample data:
import pandas as pd
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
df = pd.DataFrame({"val":[1,2,3,4],"error":[.4,.3,.6,.9]})
meansum = df["val"]
stdsum = df["error"]
plot = meansum.plot(kind='bar',yerr=stdsum,colormap='OrRd_r',edgecolor='black',grid=False,figsize=(8,2),ax=ax,position=0.45,error_kw=dict(ecolor='black',elinewidth=0.5),width=0.8)
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'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()