Black Lives Matter. Please consider donating to Black Girls Code today.

Offset graph from axis

Is it possible to shift the left boundary of the paper a bit to the right?

Right now, I have some annotations aligned along the left side of a graph (i.e. xref: 'paper', x: 0) to serve as labels for the shape regions, but I’ve run into the issue that things don’t go so well when the actual plot happens to collide with them. It looks something (exactly) like this:
plotly-annotation-overlap

See how the label is just drawn right on the bar? That’s what I’m trying to prevent. I mean, the current behaviour is correct, I don’t expect annotations to violate the contract of their entire existence and bully my graph around or anything, but if anyone has a suggestion for how I could convince the whole thing (including the x axis and its labels) to budge over by about 3 em and let the label peacefully coexist, I’d appreciate it.

Alternatively, feel free to suggest an alternative approach that keeps the meaning of the shaded regions clear if you have one; always learning new ways to datavis. :slight_smile:

You tune the range of the xaxis to shift a bit the visualization. Even if your xaxis is categorical (guessing from the screenshot, another time it’d be great if you could include a standalone code), each category is mapped to an index, for example

import plotly.graph_objects as go
animals=['giraffes', 'orangutans', 'monkeys']

fig = go.Figure([go.Bar(x=animals, y=[20, 14, 23])])
fig.update_xaxes(range=(-2, 3))
fig.show()

Okay, that sort of works as a hack, but it’s not consistent – different input lengths require different adjustments – which means it’s not really reusable. Is there really not a better way? (Also, it’s just annoying in principle to need to set an explicit range.)

Because I can’t leave well enough alone, I’ve been trying a couple other approaches. So far, everything runs into the relative scaling issue, even the (to my mind) most promising approach of using a text mode trace.

Some code with invented data:

var label = {
  x: ["",""], y: [50,150],
  mode: 'text', showlegend: false, hoverinfo: "skip",
  text: ["World Record", "Casual Average"],
  textposition: "bottom right"
};

var trace2 = {
  x: ['A', 'B', 'C', 'D', 'E', 'F'], 
  y: [50, 60, 70, 78, 78, 78], 
  type: 'bar', name: 'PB'
};

var trace3 = {
  x: ['A', 'B', 'C', 'D', 'E', 'F'], 
  y: [70, 62, 78, 84, 84, 84], 
  type: 'bar', name: 'Average'
};
var data = [label, trace2, trace3];

var layout = {
  margin: { l: 0, r: 0, t: 0, b: 0 },
  autosize: true,
  height: 300,
  xaxis: {
    title: { text: "Runner", standoff: 10, font: { size: 14 }},
    automargin: true,
    },
  yaxis: { title: "Minutes", automargin: true },
  shapes: [
    { name: "WR", xref: 'paper', yref: 'y', type: "rect",
     x0: 0, x1: 1, y0: 50, y1: 0, 
     layer: "below", fillcolor: "#80ff80", line: {width: 0}},
    { name: "Casual", xref: 'paper', yref: 'y', type: "rect",
     x0: 0, x1: 1, y0: 50, y1: 150, 
     layer: "below", fillcolor: "#ffee80", line: {width: 0}}
  ]
};

Plotly.newPlot('myDiv', data, layout, {responsive: true});

If you throw this up in a browser and resize it a bit or add more elements to trace2/3, I think it becomes clear that this isn’t a viable solution across the whole range of possible inputs.

Also note the textposition. The default is to draw the text centred both horizontally and vertically at the coordinates, but the position of the x axis is not adjusted to account for the bounding boxes of the text elements, so preventing clipping with the left edge or the chart elements to the right is difficult, and controlling their justification at the same time is effectively impossible.

I started on a subplot approach, but ran into the same issues with everything being relative, only with the added problem of convincing it to even render everything.

As an addendum, I noticed a render bug in my tinkering where the legend sometimes gets pushed off the right edge on redraw when changing thetextposition of the label trace. I haven’t pinned down a good repro, though, and I’m moving on for now. If anyone has other suggestions for guaranteeing the needed horizontal buffer for labels/annotations programmatically, or suggestions for alternative ways to express what’s shown, please feel free to chime in!

Cheers,
Wyatt