Skip to content

“Bar chart – Overlay Mode” unexpected behavior. #1973

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nyan314sn opened this issue Aug 29, 2017 · 4 comments
Closed

“Bar chart – Overlay Mode” unexpected behavior. #1973

nyan314sn opened this issue Aug 29, 2017 · 4 comments

Comments

@nyan314sn
Copy link

nyan314sn commented Aug 29, 2017

This post is related to #475

Positive and negative values can be stacked on each side of the zero line.
The problem can be replicated using codepen https://codepen.io/etpinard/pen/mPGLrY with the following code.
`console.log(Plotly.version)

    var trace1 = {
      x: ['giraffes', 'orangutans', 'monkeys','dogs'],
      y: [1, 3, -5,-2],
      name: 'SF Zoo',
      type: 'bar'
    };
    var trace2 = {
      x: ['giraffes', 'orangutans', 'monkeys','dogs'],
      y: [2, 2, 4,4],
      name: 'LA Zoo',
      type: 'bar'
    };
    var trace3 = {
      x: ['giraffes', 'orangutans', 'monkeys','dogs'],
      y: [3,1, -2,-5],
      name: 'LA Zoo',
      type: 'bar'
    };
    var data = [trace1, trace2,trace3];
    var layout = { 
      title: 'click on modebar buttons to change \'barmode\''
    };

    var config = {
      modeBarButtons: [[{
        name: 'stack',
        click: function(gd) {
          Plotly.relayout(gd, 'barmode', 'stack');
        }
      }, {
        name: 'overlay',
        click: function(gd) {
          Plotly.relayout(gd, 'barmode', 'overlay');
        }
      }, {
        name: 'group',
        click: function(gd) {
          Plotly.relayout(gd, 'barmode', 'group');
        }, 
      }, {
        name: 'relative',
        click: function(gd) {
          Plotly.relayout(gd, 'barmode', 'relative');
        }, 
      }].reverse()]
    }

    Plotly.newPlot('graph', data, layout, config);`

The output will be like this. ( You might need to click on the image to see it better. )
over_lay_mode

“Giraffes” and “orangutans” have the very similar data (1,2,3) and (3,2,1). But, the output is different depending on the order of the input. In Giraffes, trace1 and trace 2 data are never shown up and overfilled. This shouldn’t be the desired output.
What I think it should happen is that for positive values, the bars are plotted in descending order, from largest to smallest. For negative values, the bars need to be plotted in ascending order, from smallest to largest.
Please let me know if there is an easy way to fix this.

@alexcjohnson
Copy link
Collaborator

@flyingBurman I see what you're going for, and while we could certainly create something like this, it strikes me as a misleading way to display such data, normally it would be shown using barmode: 'group'. Orangutans in this plot looks like it has 1 + 1 + 1 items when they're overlaid this way. As a more extreme example, consider two traces with y values [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - using a sorted overlay you'd end up with something like:
screen shot 2017-08-29 at 5 53 20 pm
the middle two bars are almost identical data (5 & 6 vs 6 & 5) but visually there's a huge mismatch between the amount of blue and orange in each one. Bar charts are built on the (visual) size of each bar representing its data value, and I'm really reticent to break this correspondence.

Normally barmode: 'overlay' is used with trace.opacity so you can see the full size of each bar (though the mixed colors get confusing if there are more than 2 traces).

Side note: barmode: 'stack' with both positive and negative values also breaks the visual size correspondence... that's why we added barmode: 'relative' which separately stacks positive and negative values.

@nyan314sn
Copy link
Author

I have sort of workaround for my application. Let's say the data we are interested in is
1 2 3
4 5 6
7 8 9

I want to plot from first row to second row and second row to third row. The following Python code would achieve that.

    iplot(
    {'data': [{'base': array([ 1,2,3]),
       'marker': {'color': 'rgba(0, 97, 37, 1.0)',
        'line': {'color': 'rgba(0, 97, 37, 1.0)', 'width': 1}},
       'name': 'first',
       'orientation': 'v',
       'text': '',
       'type': 'bar',
       'x': array(['dog', 'cat', 'monkey'], dtype=object),
       'y': array([ 3,3,3,])},
      {'base': array([4,5,6]),
       'marker': {'color': 'rgba(138, 33, 14, 1.0)',
        'line': {'color': 'rgba(138, 33, 14, 1.0)', 'width': 1}},
       'name': 'second',
       'orientation': 'v',
       'text': '',
       'type': 'bar',
       'x': array(['dog', 'cat', 'monkey'], dtype=object),
       'y': array([ 3,3,3])}],
     'layout': {'barmode': 'overlay',
      'legend': {'bgcolor': '#F5F6F9', 'font': {'color': '#4D5663'}},
      'paper_bgcolor': '#F5F6F9',
      'plot_bgcolor': '#F5F6F9',
      'title': 'main title',
      'titlefont': {'color': '#4D5663'},
      'xaxis1': {'gridcolor': '#E1E5ED',
       'showgrid': True,
       'tickfont': {'color': '#4D5663'},
       'title': '',
       'titlefont': {'color': '#4D5663'},
       'zerolinecolor': '#E1E5ED'},
      'yaxis1': {'gridcolor': '#E1E5ED',
     
       'showgrid': True,
       'tickfont': {'color': '#4D5663'},
       'title': '',
       'titlefont': {'color': '#4D5663'},
       'zerolinecolor': '#E1E5ED'}}}
    )

This is the result.
capture

The trick is to write the lower bound as base and the difference as y values. This also takes care of the fact that having both positive and negative values screw things up, since the user has complete control over where each color starts and ends.

The main limitation that that when you hover over the bar, as you can see in the above image, the lowest bound data does not show up ( in our example that would be 1. ) How can I fix that ?

@alexcjohnson
Copy link
Collaborator

you can make a transparent first trace:

Plotly.newPlot(gd, [{
    y: [1, 2, 3],
    marker: {color: 'rgba(0, 0, 0, 0)'},
    type: 'bar'
}, {
    y: [1, 2, 1],
    type: 'bar'
}, {
    y: [2, 2, 3],
    type: 'bar'
}], {barmode: 'stack'})

screen shot 2017-08-31 at 10 11 45 am

You might also be interested in the hoverlabel attribute to control the styling of the label for the transparent trace https://plot.ly/javascript/reference/#bar-hoverlabel

@alexcjohnson
Copy link
Collaborator

@flyingBurman I think you've got workarounds to solve your particular use case, yes? I agree that it's a bit confusing, but I don't think it's a bug nor do I see a clear feature we could consider adding. I'm going to close this issue, but feel free to open a new one if you can clarify your use case as a feature request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants