Plotly.js: Add legend 'auto' x|y and/or 'container' (x|y)ref

Created on 25 Nov 2016  Â·  40Comments  Â·  Source: plotly/plotly.js

The problem occurs if the legend is positioned below (rather than to the right of) the plot area using layout = {legend: {"orientation": "h"}};. It aggravates in combination with multiline x-axis titles (using <br> tags).

Currently there's no way to control the spacing between the legend and the plotting area. Everything is auto-scaled, it is useless to set the bottom margin (layout = {margin: {"b": ...}};) in this case because it refers to the space _below_ the legend. The only way to make the whole x-axis title visible is to increase the height of the whole plot until the autoscaling sufficiently spreads the legend and the plotting area apart.

I try to illustrate the problem with the following 3 images which differ only in frame height:

_height 700px:_
example_height700

_height 1000px:_
example_height1000

_height 1300px:_
example_height1300

Here is the above plot hosted on plot.ly.

bug feature ♥ NEEDS SPON$OR

Most helpful comment

+1

Although I appreciate the great demand for a fix of this issue, I doubt that all the "+1" comments (and the thereby triggered e-mail notifications) will eventually help to motivate the plotly developers to finally implement a solution for the problem. So just use GitHub reactions to express your support, please 😉

All 40 comments

This is happening because layout.margin.b is set to 0 and the default position for horizontal legends is:

x: 0,
xanchor: 'left',
y: 1.1,
yanchor: 'bottom'

@etpinard Would it make sense to make the defaults smarter and check the value of layout.margin.b?

... and check the value of layout.margin.b?

I don't think layout.margin.b is central to this. If you play around a little with different combinations of layout.margin.b and layout.legend.yanchor, you quickly see that in the plot above you'll get nowhere desirable... actually the default of layout.legend.yanchor, which seems to be top not bottom (at least when I'm plotting in R), leads to the best results.

The problem in my eyes is that – when layout.legend.orientation is horizontal and the rest of the legend positioning parameters left to its default values – the legend overlaps the plotting area in the first place. In the default case the legend should always be placed below the x-axis, then it would be fine.

I was having a similar issue with the horizontal legend overlapping x axis values, when the x axis values were long enough, like dates. I'm adding this here because it's the only issue that comes up when you google it, and it seems related. This happens with only setting {legend: 'horizontal'} in the layout and nothing else.

legend override

I tried a couple of different things, like playing with layout.legend.yanchor and the margins, but the legend doesn't appear to be affected by margins, it stays in the same place relative to the dates, and yanchor shifts it a little bit but it remains on top of the x axis ticks.

In the end my solution was to absolutely position the legend using
legend: {
"orientation": "h",
xanchor: "center",
y: 1.2,
x: 0.5
},

This has the side effect of putting the legend on top of the graph, but you can position it below the graph by lowering the Y value. It appears that the default X and Y values according to the docs (1, 1.2) are changed to a different value when the legend is set to horizontal, which makes sense, but should also be reflected in the documentation here:

https://plot.ly/javascript/reference/#layout-legend

I chose to put it above the graph because I know my x axis values are going to change in length and the graph is being iframed into a small spot, so I don't want to waste space. Not super pretty or anything, but a reasonable workaround.

legend override 2

Hopefully the horizontal legends are changed so that it will take into account x axis tick length automatically, or there's another easy way to do it I haven't found.

I am running into this issue also.

Same Issue :(

+1

+1

+1

+1

+1

+1

+1

+1

Did they fix this issue? Does Plotly takes care of it without us having to hack around? If so how can we position the legend at bottom of chart without overlapping with x-axis?

Did they fix this issue?

Nope, I don't think so. At least when I'm plotting in R (newest CRAN version based on plotly.js 1.27.1) the issue is still the same. Also I don't think it has been fixed in newest plotly.js 1.28.3 since I can't find anything related in the changelogs.

+1

Just to report, plotly version 4.7.1, using R 3.4.1 and embedding the graph in a RNoteBook, as today, still same problem. Looking for a workaround now. Some of the examples above seem useful, will try.

None of the work arounds worked for me, it would be helpful if you report
success here if you have any

On 26 Aug 2017 17:47, "Francisco Muñoz" notifications@github.com wrote:

Just to report, plotly version 4.7.1, using R 3.4.1 and embedding the
graph in a RNoteBook, as today, still same problem. Looking for a
workaround now. Some of the examples above seem useful, will try.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/plotly/plotly.js/issues/1199#issuecomment-325139960,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AACjo5yRTlVcR4JUbUCIB_e8u6SXvcfcks5scD4KgaJpZM4K8oWX
.

+1

+1

+1

Although I appreciate the great demand for a fix of this issue, I doubt that all the "+1" comments (and the thereby triggered e-mail notifications) will eventually help to motivate the plotly developers to finally implement a solution for the problem. So just use GitHub reactions to express your support, please 😉

Any updates regarding above issue?

Digging into this a little in relation to #2243 - the background:

  • Legends are positioned in paper-referenced coordinates - those are the coordinates where the bottom left of the plotting area (excluding the margins in which we draw axis labels etc) is (0,0)
  • The default position is x=0, y=-0.1, xanchor='left', yanchor='top' - so the left edge aligned with the left edge of the plotting area, and the top in the margin, one tenth of the y axis length below the plotting area, on the theory that axis labels typically fit within that gap - but of course that's not always true!
  • So if you know the size of the plot AND the area needed for axis labels and title, you can choose legend.y such that there will be no overlap.
  • But if you need this to work with dynamic plot size or axis label length, the auto-margin mechanism we have (which is used right now to increase the margin in order to keep the legend from extending outside the visible area and will soon be used to ensure long axis labels are always visible, see #2243), CANNOT be used as is to keep the legend from overlapping axis labels.

I see two possible ways to go here. The first is less of an addition to what we currently have, but the second I think would be more powerful and probably easier to implement too:

  1. Have the auto-margin system automatically change legend.y. When legend.y is not explicitly set, it would have to have an 'auto' value or something, then the auto-margin system would have to figure out how to combine space needed for the axis labels with space needed for the legend. But this is still problematic: what if you want it at the top and you have a top x axis whose labels it needs to avoid? Would we need 'auto-top' and 'auto-bottom'? That sounds awkward, and there may be other possibilities I'm not thinking of.
  2. Alternatively, allow the legend to be positioned in other coordinates - I'm thinking of the 'container' coordinates as proposed in #882 for chart titles, in which (0,0) is the absolute bottom left corner including margins. Then we could default a horizontal legend to x=0, xanchor='left', xref='paper' (that wouldn't change) and y=0, yanchor='bottom', yref='container' (that part is new, though the result would be about the same as what we have now. In addition we could add pad attributes as also suggested in #882, which would add a pixel buffer between the legend and the edge of the div, and between the legend and the plot or axis labels) - and at that point, the auto-margin system could simply reserve space for anything container-referenced (including the title 🎉 ) before fitting the other things in.

@nicolaskruchten @etpinard

Any chance this is being worked on? Would be pretty clutch for my project.

Was there any work being done on this or perhaps another issue that led to a fix?

Another example from https://github.com/plotly/plotly.js/issues/4261


When there are a large number of traces in a horizontal legend, they begin to overlap to x-axis label as the legend grows in size. It would be great if the horizontal legend added a scrollbar if there are >3-4 rows of legend items, or if this could be configurable.

This seems somewhat related to this issue: https://github.com/plotly/plotly.js/issues/960

image

Any word on a fix for this?

We are chipping away at various pieces of this problem and related problems... no commitment on timelines at this time :)

My feeling is that with *axis.automargin = true, the margin pushing code should take into account the legend in cases when it's in horizontal mode below the plot, leaving room for legend plus the axis/tick labelling, rather than taking the max as we currently do, thereby allowing them to overlap. I think we should resolve #4222 the same way. This would allow us to not add extra attributes or auto-layout modes.

Maybe we could do this only in cases where the legend positioning is outside of [0-1] or something, so that people could still place legends within the plotting area on purpose?

the margin pushing code should take into account the legend in cases when it's in horizontal mode below the plot, leaving room for legend _plus_ the axis/tick labelling,

Leaving room for both the tick labels and the legend in the margin wouldn't be too hard, but the hard part here (which we might need a new attribute for) is to reposition the legend below the ticks. The new legend position will depend on the tick label dimensions and thus we would have to introduce some new cross-component logic.

The new legend position will depend on the tick label dimensions

Is the mechanism here because longer labels means pushing the margins up means in effect moving the (0,0) coordinate that the paper/domain coordinate space works within?

I think I'm understanding the problem and suggested solutions better now... the container ref idea sounds like a pretty good one as a low-level control system. We may want to layer on top of that a "placement" enum that would be the 4 corners and 4 faces of the rectangle, which would automatically set anchors and refs to container etc so that orientation="h" with placement="bottom center" would do the right thing and play well with automargins?

Moved to 1.53.0

Is there any update on this? I have some legends with a lot of text, the text is dynamic, so I can't do much about hose long the text is. When the chart generates, the legend overlaps the x-axis legend considerably.

Is there anything the community can do to help?

If someone wants to take on some implementation work, we'd be happy to iterate on a design and review some PRs, but at the moment this is no longer on our short-term roadmap.

If you work for an organization with a software budget, you could sponsor this feature to bump it up our priority list.

  1. I didn't know sponsoring a feature could be a thing
  2. I'll try to take a look to help out

Great! :)

This issue has been tagged with NEEDS SPON$OR

A community PR for this feature would certainly be welcome, but our experience is deeper features like this are difficult to complete without the Plotly maintainers leading the effort.

Sponsorship range: $10k-$15k

What Sponsorship includes:

  • Completion of this feature to the Sponsor's satisfaction, in a manner coherent with the rest of the Plotly.js library and API
  • Tests for this feature
  • Long-term support (continued support of this feature in the latest version of Plotly.js)
  • Documentation at plotly.com/javascript
  • Possibility of integrating this feature with Plotly Graphing Libraries (Python, R, F#, Julia, MATLAB, etc)
  • Possibility of integrating this feature with Dash
  • Feature announcement on community.plotly.com with shout out to Sponsor (or can remain anonymous)
  • Gratification of advancing the world's most downloaded, interactive scientific graphing libraries (>50M downloads across supported languages)

Please include the link to this issue when contacting us to discuss.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bryaan picture bryaan  Â·  3Comments

tim-sauchuk picture tim-sauchuk  Â·  3Comments

etpinard picture etpinard  Â·  3Comments

HunterMcGushion picture HunterMcGushion  Â·  3Comments

pynklu picture pynklu  Â·  3Comments