Plotly.js: Word wrap for long labels

Created on 1 Apr 2016  Â·  6Comments  Â·  Source: plotly/plotly.js

Is there an option to reflow long text labels?

  • For example, a long label without reflow (plotly tries to autocorrect by slanting the labels instead of reflowing the text, but it still doesn't fit)
    plotlylonglabels1
  • And a simple manual fix with a few <br> in the code that I'd like to have Plotly be able to do with a simple wrap: true option
    plotlylonglabels2

JS code for this chart

var data = [{
// first screenshot labels
    //x: ['giraffes', 'orangutans', "Very Long Text Label That Doesn't Fit Properly"],
// second screenshot labels
    x: ['giraffes', 'orangutans', "Very Long<br>Text Label That<br>Doesn't Fit<br>Properly"],
    y: [20, 14, 23],
    type: 'bar'
}]
Plotly.newPlot('PlotlyDivSimple', data, {})
community feature

Most helpful comment

Ok, understood. Would help with a PR if I had a clue how to do that :)

Pardon my ignorance, but is there no way to introduce a JavaScript function that would be applied to all labels before they're fed to SVG/WebGL, where it becomes complicated?
For example, I've google-found this function (it's not great since there is an issue with long words, but just as an illustration)

function stringDivider(str, width, spaceReplacer) {
    if (str.length>width) {
        var p=width
        for (;p>0 && str[p]!=' ';p--) {
        }
        if (p>0) {
            var left = str.substring(0, p);
            var right = str.substring(p+1);
            return left + spaceReplacer + stringDivider(right, width, spaceReplacer);
        }
    }
    return str;
}

that I can use internally to shorten the labels

var label = "Very Long Text Label That Doesn't Fit Properly"
x: ['giraffes', 'orangutans', stringDivider( label, 20, "<br>") ],

Also, as a side question — is there a way to read the bar width in plotly so I don't have to adjust the width manually and can make it reflow properly when chart size is adjusted.

All 6 comments

Unfortunately, there isn't this option built into plotly.js at the moment. The text labels are created using SVG elements, or in WebGL where text-reflow is done manually and it's not _quite_ as easy just constraining the width.

This likely won't be of high priority for us in the _immediate_ future, but we're always open to pull requests and are happy to help on them!

Ok, understood. Would help with a PR if I had a clue how to do that :)

Pardon my ignorance, but is there no way to introduce a JavaScript function that would be applied to all labels before they're fed to SVG/WebGL, where it becomes complicated?
For example, I've google-found this function (it's not great since there is an issue with long words, but just as an illustration)

function stringDivider(str, width, spaceReplacer) {
    if (str.length>width) {
        var p=width
        for (;p>0 && str[p]!=' ';p--) {
        }
        if (p>0) {
            var left = str.substring(0, p);
            var right = str.substring(p+1);
            return left + spaceReplacer + stringDivider(right, width, spaceReplacer);
        }
    }
    return str;
}

that I can use internally to shorten the labels

var label = "Very Long Text Label That Doesn't Fit Properly"
x: ['giraffes', 'orangutans', stringDivider( label, 20, "<br>") ],

Also, as a side question — is there a way to read the bar width in plotly so I don't have to adjust the width manually and can make it reflow properly when chart size is adjusted.

Any update on this?

@mdtusz I'm happy to try to help with this if you're able to point me in the right direction in the codebase.

https://github.com/plotly/plotly.js/pull/1834 should see some foundation work on this.

A workaround is to line break svg elements after rendering. This assumes that there are <br/> tags in the text, and splits text elements into multiple text elements.

      var insertLinebreaks = function (d) {

        if (typeof d.text === 'string') {
          var words = d.text.split(/<br[/]?>/);
          var el = d3.select(this);
          el.text('')
          for (var i = 0; i < words.length; i++) {
            var tspan = el.append('tspan').text(words[i]);
            if (i > 0)
              tspan.attr('x', 0).attr('dy', '15');
          }
        }
      };   

Then it's a matter of selecting svg text elements and calling the above function:

d3.select('#c_Q1 svg').selectAll('g text').each(insertLinebreaks);

You can get fancier with the selector so line break just axis labels for instance.

It could also be used in conjunction with above method by @eugenesvk to evaluate long strings and insert such line break markers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

etpinard picture etpinard  Â·  3Comments

chriddyp picture chriddyp  Â·  3Comments

emanuelsetitinger picture emanuelsetitinger  Â·  3Comments

nicolaskruchten picture nicolaskruchten  Â·  3Comments

archmoj picture archmoj  Â·  3Comments