I'm converting an antiquated Matplotlib script that's written for Python 2.7
and Matplotlib 1.3.1
(legacy MacOS Python implementation) to Python 3
and Matplotlib 3.5.1
. Unfortunately, I can't provide a reproducible example as the code is proprietary (I've tried to reproduce the error from scratch, but haven't been able to.) so apologies for the lack on an MVCE.
I'm getting the following error when I send the plot to savefig
on an area chart:
Traceback (most recent call last):
File "chart_area.py", line 323, in <module>
chart_tools.save(logger=LOG)
File "/Users/Dave/PycharmProjects/matplotlib/chart_tools.py", line 1053, in save
plt.savefig(
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/pyplot.py", line 859, in savefig
res = fig.savefig(*args, **kwargs)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/figure.py", line 2311, in savefig
self.canvas.print_figure(fname, **kwargs)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/backend_bases.py", line 2210, in print_figure
result = print_method(
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/backend_bases.py", line 1639, in wrapper
return func(*args, **kwargs)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/backends/backend_agg.py", line 509, in print_png
FigureCanvasAgg.draw(self)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/backends/backend_agg.py", line 407, in draw
self.figure.draw(self.renderer)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/figure.py", line 1862, in draw
self.patch.draw(renderer)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/patches.py", line 587, in draw
draw_path(tpath, affine,
File "/Users/Dave/Library/Python/3.8/lib/python/site-packages/matplotlib/patheffects.py", line 100, in draw_path
path_effect.draw_path(self._renderer, gc, tpath, affine,
AttributeError: 'str' object has no attribute 'draw_path'
The savefig
call is:
plt.savefig(f"{payload['p_dict']['chartPath']}{payload['p_dict']['fileName']}", **payload['k_dict']['k_plot_fig'])
The save path is (type = string) and the kwargs are dirt simple (type = dict):
{'bbox_extra_artists': None, 'bbox_inches': None, 'format': None, 'frameon': None, 'orientation': None, 'pad_inches': None, 'papertype': None, 'transparent': True}
The relevant lines from matplotlib's draw_path.py
are:
def draw_path(self, gc, tpath, affine, rgbFace=None): # 98
for path_effect in self._path_effects: # 99
path_effect.draw_path(self._renderer, gc, tpath, affine, # 100
rgbFace)
I have no idea whatsoever why the path_effect
object is coming across as a string.
The same project has a text-only chart which uses the same savefig
method call and doesn't produce the error. As far as I can tell, there are no animations in the entire project. I've tried both with and without kwargs and get the same error. A possibility might be something in plt.rcParams
or a style sheet but I suspect (e.g. don't know) that there is something being passed to an axes
or subplot
that's the culprit. I suppose it's also possible that the stacktrace is a red herring and theres a bytes/strings problem somewhere. I'm stumped.
UPDATE 1:
I modified patheffects.py
to inspect the payload that was coming through the draw_path()
method:
object | type | value |
---|---|---|
self._path_effects |
list | ['[]'] |
path_effect |
string | '[]' |
I tried converting the path_effect
object to a list object using literal_eval, but then got the following traceback:
AttributeError: 'list' object has no attribute 'draw_path'
I'm beginning to suspect that there might be a bug in the version of matplotlib I'm using 3.5.1
CodePudding user response:
Turns out the source of the error is a style sheet entry. matplotlib expects lists to be passed without [
or ]
(and be comma separated). When matplotlib encounters []
it doesn't interpret it as a list. An empty list would be represented as:
path.effects:
and not what I was working with:
path.effects: []
A properly formatted list parm would be:
some.thing: 1, 2, 3, 4, 5