tikzplotlib
tikzplotlib copied to clipboard
Errorbar legend not working
Hi. First thanks for the great package. I have run into an issue that may be related to #86 (though I'm not sure). It appears that adding a legend to an errobar plot throws an invalid RGB error.
import matplotlib.pyplot as plt
from matplotlib2tikz import save
import numpy as np
def main():
x = np.linspace(0,1,3)
y = x
yerr = 0.5*np.ones(3)
fig, ax = plt.subplots()
ax.errorbar(x, y, yerr=yerr, label='$test$')
ax.legend(loc=2)
fig.savefig('test.pdf')
save('test.tex')
if __name__ == '__main__':
main()
If ax.legend() is called the code fails to run past the fig.savefig call. If the legend is not called the code works as expected, but of course does not generate the legend. The output TeX when the legend is not active is as expected.
I should note I'm using Python 2.7, matplotlib v2.1.1, and matplotlib2tikz v0.6.14
With Python 3.6, matplotlib v3.0.2 and matplotlib2tikz v0. 7.4 (in anaconda environment), the legends do work. But if I plot two curves, all the legend texts get set to the second one. And if I tweak the error bars (capsize, capthick keywords), each of those gets its own legend as well. The generated pdf turns out perfectly fine. I can remove the excess legends and correct the legend text manually in the tex file, but then I'm left with only lines as legend symbols. Python code:
import sys
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib2tikz
#plt.style.use("ggplot")
sns.set_context('talk', font_scale=1)
sns.set(style='ticks')
sns.set_style({'xtick.direction': 'in','ytick.direction': 'in'})
#plt.rc('text', usetex=True)
plt.rcParams['mathtext.fontset'] = 'custom'
plt.rcParams['mathtext.rm'] = 'Liberation Sans Narrow'
plt.rcParams['mathtext.it'] = 'Liberation Sans:italic'
plt.rcParams['mathtext.bf'] = 'Liberation Sans:bold'
#plt.rc('font', family='sans', serif='cm10')
plt.rcParams['text.latex.preamble'] = [r'\boldmath']
def main():
df1 = pd.read_pickle('data_0.pickle')
df2 = pd.read_pickle('data_1.pickle')
fig, ax = plt.subplots()
x1 = df1['z'].tolist()
y1 = df1['avg'].tolist()
yerr1 = df1['e'].tolist()
x2 = df2['z'].tolist()
y2 = df2['avg'].tolist()
yerr2 = df2['e'].tolist()
ax.set_xlim(0, 4.1)
ax.errorbar(x1, y1, yerr=yerr1, capsize=2, capthick=1, label='CG')
legend1 = ax.legend()
ax.errorbar(x2, y2, yerr=yerr2, capsize=2, capthick=1, label='AA')
legend2 = ax.legend()
plt.xlabel(r"$\mathbf{z\ [nm]}$")#, fontsize='26'
plt.ylabel(r"$\mathbf{G(z)\ [kcal/mol]}$")#, fontsize='26'
fig.savefig(sys.argv[1] + '.pdf')
matplotlib2tikz.save(sys.argv[1] + '.tex')
if __name__ == '__main__':
main()
PDF image: test.pdf
Has there been an attempt to use pgfplot's own error bar style instead of creating additional plots and paths? I haven't looked into how these plots are parsed in detail yet, but this would in theory solve the above issue and also increase readability and usability of the Tex file.
As of version 0.9.6, there is still the bug where using errorbar will result in the same legend label being used for each line.
Minimal example:
import tikzplotlib
from matplotlib import pyplot as plt
figure, axes = plt.subplots()
axes.errorbar(x=[1], y=[1], yerr=[0.5], label='data0')
axes.errorbar(x=[2], y=[2], yerr=[0.5], label='data1')
axes.legend()
tikzplotlib.save('check.tikz')
This results in the tikz file having the label of "data1" for each errorbar line.
I found a workaround for the repeated label case. It seems errorbar creates a collection object which does not contain the legend label where tikzplotlib expects the legend label to appear. As a workaround, you can explicitly set the legend label in the errorbar collection where tikzplotlib expects to find it.
import tikzplotlib
from matplotlib import pyplot as plt
figure, axes = plt.subplots()
error_bar0 = axes.errorbar(x=[1], y=[1], yerr=[0.5], label='data0')
error_bar0[0].set_label('data0')
error_bar1 = axes.errorbar(x=[2], y=[2], yerr=[0.5], label='data1')
error_bar1[0].set_label('data1')
axes.legend()
tikzplotlib.save('check.tikz')
@golmschenk Thanks for your workaround! Here is a workaround for repeated entries due to tweaked error bars:
import tikzplotlib
from matplotlib import pyplot as plt
figure, axes = plt.subplots()
error_bar0 = axes.errorbar(x=[1], y=[1], yerr=[0.5], label='data0', capsize=3)
error_bar1 = axes.errorbar(x=[2], y=[2], yerr=[0.5], label='data1', capsize=3)
# delete all labels
axes.legend([])
# add the desired ones
error_bar0[0].set_label('data0')
error_bar1[0].set_label('data1')
axes.legend()
tikzplotlib.save('check.tikz')
You can also have a look at my pull request. I implemented the translation of container objects into proper pgfplots error bar styles.