Skip to content

explicit bar positioning and width #80

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
alexcjohnson opened this issue Dec 7, 2015 · 21 comments
Closed

explicit bar positioning and width #80

alexcjohnson opened this issue Dec 7, 2015 · 21 comments
Labels
feature something new
Milestone

Comments

@alexcjohnson
Copy link
Collaborator

There are a number of use cases for explicit control over bar widths and positions (horizontal and vertical). I'm thinking about this in the context of waterfall plots, irregular-width bars but also times when the auto width is wrong (eg bar positions 1, 3, 5 and you want width 1, not width 2...), complex groupings (a stack of several traces, grouped with another stack of several other traces, etc).

If we allow explicit position and size, that covers every degree of freedom that exists for drawing bars on a plot. Then later we can peel off pieces with more meaning (like complex groupings that we should be able to describe in terms of grouping and stacking rather than positioning), and provide a simpler syntax for those.

I'm thinking of attributes:

// width of bars, in units of the position axis data
// This would override the whole automatic width machinery,
// including bargap and bargroupgap
width: {
    valType: 'number',
    min: 0,
    arrayOk: true
},
// shift on the position axis, in units of the position axis data
// This would override the automatic positioning machinery
// in the case barmode='group', rather than add to it.
offset: {
    valType: 'number',
    arrayOk: true
}
// shift of the bottom of the bar on the size axis
// This would override the automatic stacking machinery,
// rather than add to it.
base: {
    valType: 'any'
    arrayOk: true
}

Are offset and base clear enough? Any better names? And is width OK even for horizontal bars (in which case it's really the bar height)?

@mdtusz
Copy link
Contributor

mdtusz commented Dec 7, 2015

barweight or thickness maybe?

@etpinard
Copy link
Contributor

etpinard commented Dec 7, 2015

Adding these three attributes sounds like the way to go.

I like thickness better than width. base and offset are as good as it gets I think.

Adding attribute aces @cldougl @chriddyp for their input.

@etpinard etpinard added the feature something new label Dec 7, 2015
@alexcjohnson
Copy link
Collaborator Author

barweight or thickness maybe?

barweight seems ambiguous to me, I almost expect it to mean how opaque it is or something. thickness could be OK, though somehow I associate that with lines (even though we use width for line thickness. go figure.)

@cldougl
Copy link
Member

cldougl commented Dec 7, 2015

👍 for adding these attributes! base and offset seem pretty clear to me. Right off the bat thickness seems like more of a stylistic attribute than one that would represent data like in the irregular-width bars. width makes sense to me, but that could be just because I saw irregular-width bars.

@cpsievert
Copy link

👍 from me as well. With this I could correctly convert ggplot2's geom_bar() in all cases.

@krishna-agarwal
Copy link

Is this feature implemented?

@etpinard
Copy link
Contributor

@krishna-agarwal no. We close issues as soon as a feature is implemented (or a bug is fixed).

@n-riesco
Copy link
Contributor

n-riesco commented Oct 5, 2016

@alexcjohnson I'm working on this issue and on #475. I wanted to check with you whether I understand base and offset correctly.

This is how I understand it: if a trace sets either base or offset, the trace is excluded from the barmode machinery;. i.e. we would position the trace as if barmode was overlay and then shift horizontally and vertically according to base and offset. Is this correct?

@etpinard
Copy link
Contributor

etpinard commented Oct 5, 2016

@n-riesco

This is how I understand it: if a trace sets either base or offset, the trace is excluded from the barmode machinery;. i.e. we would position the trace as if barmode was overlay and then shift horizontally and vertically according to base and offset. Is this correct?

That's how I see it. 👍

@alexcjohnson
Copy link
Collaborator Author

@n-riesco I think it could be useful to treat the different aspects separately. So with barmode='group', normally base is 0 and width and offset are set automatically per trace in the group. But if you only provide an explicit base, you could still get the automatic width and offset, which could be useful for a multiple waterfall plot, where you want to show components adding and subtracting vertically to arrive at a total, but still grouped horizontally. For example: http://wiki.analytica.com/images/b/b3/Waterfall_chart_example.png
waterfall_chart_example

In barmode='stack' the case is not so clear to me... why would you want to tweak width or offset while retaining automatic base from the stacking? Maybe you want skinny bars stacked on top of fat bars? Dunno, but I don't see a reason to forbid it. Same in 'group' mode if you want to use the offset machinery but explicitly override width... would be weird but I think it's clear what the intent of the user is in this case.

BUT it does seem like if you override the key attribute that's aggregated per trace (base in 'stack' mode, offset in 'group' mode) then you're right, that trace should get removed from the aggregation and treated as 'overlay' so the other traces stack or group without it.

@n-riesco
Copy link
Contributor

n-riesco commented Oct 6, 2016

@alexcjohnson If base, offset and width are allowed to interact with the group, stack and relative modes. I reckon I'll have to create a setPosition for each mode. This isn't a problem. In fact, I think it'll make setPostion more readable.

Here are a few more questions about the interactions with barmode:

  • in group mode, if width is set, the algorithm to compute offset needs to account for this setting. Currently, the offset is set per trace and stored in t.poffset, whereas width in this spec can be set per point (I guess I'd have to move poffset to each point).
  • in stack/relative mode, if width is set, what would be the alignment? left-aligned?
  • in stack/relative mode, if offset or width are set, do we allow adjacent bars to overlap?

Another question about width. This spec says the width is given in position units. How would this work when the data are categories?

@etpinard
Copy link
Contributor

etpinard commented Oct 6, 2016

[...] I reckon I'll have to create a setPosition for each mode. I think it'll make setPostion more readable.

great 👍

(I guess I'd have to move poffset to each point)

That's correct.

on stack/relative mode, if width is set, what would be the alignment? left-aligned?

I'd vote for left-aligned. This is probably what most users would expect.

in stack/relative mode, if offset or width are set, do we allow adjacent bars to overlap?

Yes, allowing overlap is fine. We shouldn't try to be too magical when users set offset and width.

How would this work when the data are categories?

At the moment, data-referenced annotations on categorical axes are placed using their calculated coordinates (which are integers corresponding to each category position - see example: http://codepen.io/etpinard/pen/qaxBQv). So, I'd vote for keeping the same semantics for bar width.

@alexcjohnson
Copy link
Collaborator Author

@n-riesco I agree with @etpinard on all points except

on stack/relative mode, if width is set, what would be the alignment? left-aligned?

I'd vote for left-aligned. This is probably what most users would expect.

Most or all of the rest of the user-facing bar positioning is centered, so I'd keep it that way.

@n-riesco
Copy link
Contributor

@alexcjohnson @etpinard

While playing with mock images for this feature, I noticed that it's a bad idea to set base if any of the bar sizes is negative, because a bar with a custom base b and size -s, is indistinguishable from a bar with custom size b-s and size s.

Negative bar sizes are already an issue in stack barmode (I guess this is the reason why the barmode relative was introduced).

At the moment plotly.js does nothing about negative bar sizes in stack mode, and so I've opted to do nothing when when base is set. Shall we do anything about it? Perhaps add a note in the description of the base attribute?

@alexcjohnson
Copy link
Collaborator Author

It's true that this is in general ambiguous, though there are two reasons I think we should allow it:

  • In context it's often clear - for example in the waterfall example above, the depreciation, O&M, and tax bars would generally be negative but using the preceding subtotal as the base, and having that subtotal right next to it, it's clear which end of the bar is its start and which its end.
  • Our hover text should still show up at the end no matter what. Doesn't help viewers of the static plot, but that will disambiguate it for online viewers.

@etpinard
Copy link
Contributor

done in #1075

@AdnanBoota
Copy link

Can i increase the bar widths with the x axis type as "date"?

The idea is to have a single bar value (with large width) for multiple hours on time series.

Right now i am doing it on the numerical values, but i want to implement it on time series. Please check and let me know what is best solution for this implementation.

imagen

@alexcjohnson
Copy link
Collaborator Author

@AdnanBoota you might just need layout.bargap

Plotly.newPlot(gd, [{
    x: ['2017-01-02', '2017-01-03', '2017-01-04'],
    y: [2, 4, 3],
    type: 'bar'
}], {bargap: 0})

but if you really do need explicit widths on a date axis, you can specify them as milliseconds:

Plotly.newPlot(gd, [{
    x: ['2017-01-02', '2017-01-03', '2017-01-04'],
    y: [2, 4, 3],
    type: 'bar',
    width: 1000*3600*23 // 23 hours
}])

@saimaparveen
Copy link

saimaparveen commented Feb 7, 2018

@alexcjohnson Using the above code bar width is fixed, but tooltip is misplaced.
https://codepen.io/saimaparveen/pen/zRKXge
You have any fix for tooltip also?

@alexcjohnson
Copy link
Collaborator Author

@saimaparveen you can use layout.hovermode: 'closest'. We should really just make that the default (see #778) but you're right that in this particular case, there's no reason hovermode: 'x' should move the hover label way out there. I'll make a new issue for it so it doesn't get lost in this closed issue.

@majorrabbit
Copy link

Any plans to implement this same functionality for box type?

It would provide a better workaround to do grouping for #78 and #2097 via explicit width and offset with boxmode 'overlay' since boxmode 'group' is not working with a second y-axis.

The current workaround referenced in #78 still leaves a ghost trace and the group spacing shows a gap where the hidden trace is (between the yaxis and yaxis2 plot groupings), explicit offset and width could adjust them perfectly and without needing a 'dummy' trace...

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

No branches or pull requests

10 participants