0

I'm using xarray in python to plot a DataArray with several panels containing each of them plotting several lines (hue). By default, the location of the legend is set on the right of the panels. I'm trying to find a way to move it to the top or bottom of the panels.

I have no issue doing that with plot.pcolormesh, as the argument cbar_kwargs={'orientation': 'horizontal'} works well, but does it exist something similar with plot.line()? I've looked at the documentation and I couldn't find anything regarding that.

As an example, this is code I use (it is very straightforwards):

p = dataArray.plot.line(
    y="z",
    hue="source",
    col="t",
    col_wrap=4,
)
plt.gca().invert_yaxis()
plt.draw()
plt.show()

Which produces this figure.

Thanks for your help.

Edit. Following advises from somewhere else, I explored a bit the problem.

Xarray creates a FacetGrid object (from seaborn lib). This object contains a function to automatically add a legend (which is used by xarray) to expand the figure with a right panel where the legend object is drawn. I figured out how to access this object (p.figlegend) which itself has the attribute set_bbox_to_anchor which indeed allows to move the legend... but only relative to this additional panel.

Now that I have the legend object, I could totally move it where ever I want, but this is not really the option I was looking for. Firstly, if I do that I will have to create the legend object from scratch, which is what I wanted to avoid by using xarray automatic line plot, secondly I will have a small empty panel on the right of my figure. At this point creating the figure from subplot & making the panels one by one would be easier.

I think my issue could be simply reduced to: is it possible to have a FacetGrid object that draw the legend under or over the figure instead of on the right? If not, there is probably no simple way to do what I want to do.

Nathan G.
  • 9
  • 2
  • See [this](https://stackoverflow.com/a/4701285/4690237) post for how to move matplotlib legends around. – falafelocelot Jun 08 '21 at 12:22
  • Thanks, but as I use xarray automatic layout to plot my figure, it's not that simple. How can I access the ax that contains the matplotlib legend? Of course, I could use subplot and manually plot all subplots by specifying the axes, but this is not what I'm trying to do here. I was really hoping for a solution that does not involve building the figure from zero. – Nathan G. Jun 08 '21 at 12:29
  • Maybe you can use seaborn's `sns.move_legend()`? See [Legend handle to an xarray plot](https://stackoverflow.com/questions/70940962/legend-handle-to-an-xarray-plot). – JohanC Feb 01 '22 at 14:18
  • Thanks for you feedback. Sorry for the late come back, it took me a while before I was able to go back to this project. Sadly, it doesn't work on FacetGrid object. fig.gca() has no legend associated. I guess I will have to dig a bit to figure out where the figure is exactly. I tried my fig.figlegend() trick, but it doesn't send an object that seaborn is capable to deal with. – Nathan G. Mar 10 '22 at 14:36

1 Answers1

0

I don't have your data but this should work:

p = dataArray.plot.line(
    y="z",
    hue="source",
    col="t",
    col_wrap=4,
add_legend=False
)
p.add_legend(bbox_to_anchor=(0.5, -.05),
          ncol=5)

You don't automatically create the legend, so you put add_legend=False in the call of plot.line() but then you add it and pass your options. You will need to play with bbox_to_anchor location, and with ncol. I put 5 because in the example you gave you had 5 lines.

the horizontal option is available in pcolormesh because that is a colorbar, not a legend. In fact, even outside of xarray you don't have a horizontal option for the legend, if I am not mistaken, you have it only for a colorbar.

Hope this helps!

claude
  • 549
  • 8
  • 25