tikzplotlib icon indicating copy to clipboard operation
tikzplotlib copied to clipboard

Errorbar legend not working

Open alexfeld opened this issue 7 years ago • 6 comments
trafficstars

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

alexfeld avatar Jan 07 '18 23:01 alexfeld

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

Bernadette-Mohr avatar Apr 22 '19 08:04 Bernadette-Mohr

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.

Naikless avatar Jun 23 '20 08:06 Naikless

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.

golmschenk avatar Jun 04 '21 16:06 golmschenk

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 avatar Jun 04 '21 18:06 golmschenk

@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')

juliandoerner avatar May 12 '23 18:05 juliandoerner

You can also have a look at my pull request. I implemented the translation of container objects into proper pgfplots error bar styles.

Naikless avatar May 12 '23 21:05 Naikless