Skip to content
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

Ternary (and scatter) fill #462

Merged
merged 11 commits into from
Apr 22, 2016
Merged

Ternary (and scatter) fill #462

merged 11 commits into from
Apr 22, 2016

Conversation

alexcjohnson
Copy link
Collaborator

@etpinard @mdtusz this still needs tests, but please comment on the functionality and names of the new fill modes:

  • added two new fill modes to regular scatter: toself and tonext
    • toself just takes each segment (sequence of points with no missing values) and closes it on itself. We had hacked this before with tozeroy I think, don't have to do that anymore. Note that this closes with a straight line (and only closes the fill, not the line) no matter what line.shape you have. If you want the line to close, just repeat the first point at the end of each shape.
    • tonext behaves just like toself for the first trace, but for subsequent traces it adds the previous trace's fill path in reverse. This is only really useful if either trace fully encloses the other (ie manually constructed contour lines), then it fills between them. If that's not the case, you shouldn't be using this mode, it will basically fill BOTH traces.
      screen shot 2016-04-22 at 12 25 38 am
Plotly.newPlot(Tabs.getGraph(), [
    {x: [1,2,3,null,4,5,6], y: [1,2,1,null,2,3,2], fill: 'tonext'},
    {x: [-1,4,9], y: [0,5,0], fill: 'tonext'}])
  • for scatterternary, these are the only available fill modes.
    screen shot 2016-04-22 at 12 21 43 am
Plotly.newPlot(Tabs.getGraph(), [
    {a: [.4,.4,.2,.4], b: [.2,.4,.4,.2], type: 'scatterternary', fill: 'tonext'},
    {a: [.5,.5,0,.5], b: [0,.5,.5,0], type: 'scatterternary', fill: 'tonext'}])

these fill modes have a limitation for line.shape='spline': you will in general get a kink at the closing point. Maybe we'd prefer to have these modes automatically close lines, and use drawing.smoothclosed for splines, as we do for contours anyway? Or perhaps we don't automatically close any lines, but if we see a spline that starts and ends on the same point we convert it to smoothclosed? I think that may be the way to go actually - because there is an important use case for unclosed line with closed fill: contours going off the edge of a plot.

And as a side note, I think ternary plots should have gridlines by default... they look weird without them, and you really need them to make sense of the axes - or at least I do, dunno about chemists who look at these every day...

@jackparmer
Copy link
Contributor

@chriddyp @bpostlethwaite let's get this baddy into the Plotly 2.0 editor! 🔺 ✊

@@ -152,7 +152,7 @@ module.exports = {
},
fill: {
valType: 'enumerated',
values: ['none', 'tozeroy', 'tozerox', 'tonexty', 'tonextx'],
values: ['none', 'tozeroy', 'tozerox', 'tonexty', 'tonextx', 'toself', 'tonext'],
dflt: 'none',
role: 'style',
description: [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be a good time to add more info the description field.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 added. It takes a lot to describe this behavior...

@etpinard
Copy link
Contributor

perhaps we don't automatically close any lines, but if we see a spline that starts and ends on the same point we convert it to smoothclosed

Sounds like the way to go from my 👀 too.

I think ternary plots should have gridlines by default

I agree 100%.

but please comment on the functionality and names of the new fill modes

👍 from me. Bring on some test cases!

'*tonext* fills the space between two traces if one completely',
'encloses the other (eg consecutive contour lines), and behaves like',
'*toself* if there is no trace before it. *tonext* should not be',
'used if one trace does not enclose the other.'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fantastic.

@etpinard
Copy link
Contributor

@alexcjohnson

Consider:

var data = Object.keys(rawData).map((k, i) => {
    var pts = rawData[k];

    return {
        type: 'scatterternary',
        name: k,
        mode: 'lines',
        a: pts.map(d => d.clay),
        b: pts.map(d => d.sand),
        c: pts.map(d => d.silt),
        line: { color: '#444' },
        fill: 'tonext',
        fillcolor: colors[i]
    };
});

image

Is there a way to ensure the line are always above the fills?

That is, to make this line

image

appear as wide as without fill turned on.

"data":[
{
"x": [1, 2, 3, 1, null, 4, 5, 6],
"y": [2, 3, 2, 2, null, 3, 4, 3],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great test mock.

@etpinard
Copy link
Contributor

etpinard commented Apr 22, 2016

@alexcjohnson and perhaps ternary fills should be below the grid lines, e.g.

image

EDIT: that would require some trickery in scatter/plot.js. Maybe that's too much to ask for at this stage.

@alexcjohnson
Copy link
Collaborator Author

@etpinard

Is there a way to ensure the line are always above the fills?

I'm not quite sure what that raw data is... but if you make each region fill: 'toself', with all the lines set the same, AND you make sure all the polygons are explicitly closed (so you may need to repeat the last point?), then the lines should all be consistent width, I would think? That half-width effect comes only when there's an edge that doesn't have a line on it, abutting a trace underneath it (or with fill: 'tonext', a trace more than one below it... which is going to happen a lot in this kind of diagram). I don't think you can just say "lines are always above fills" which is what you'd need to do in order to get consistent width without duplicate edges, because if there are overlapping regions, you want the lower one covered up completely, not covering up the fill but letting the line show through.

Another way to construct this is to make the filled traces with NO lines, then add a trace on top of them all with the lines and no fill. Then you can get away without duplicating any edges.

and perhaps ternary fills should be below the grid lines

For now, semitransparent fills can let the gridlines shine through.

We might make an option in layout.ternary for whether to draw gridlines above or below the data. I don't think we want it always this way, because markers normally should go in front of the gridlines. And if we try to make the markers in front but the fills in back, then what happens when there's a fill in one trace that should cover some markers in a previous trace (same issue as with the lines)? But if we make such an option, then we could set its default smartly... maybe if any trace has opaque fill we put the gridlines in front?

This option would also interact with what we were talking about the other day with clipping (or not) the markers to the edge of the plot. My proposal, for the record, was that for any side with min=0 we should NOT clip the trace at that edge, so you can see the full marker drawn on top of the axis line if there is one, but as soon as min>0 we should start clipping on that edge. But if the gridlines are on top, I think we would need to clip on all edges no matter what, otherwise you'd see half a marker peeking out from behind the gridlines and it would look weird.

@etpinard
Copy link
Contributor

@alexcjohnson

AND you make sure all the polygons are explicitly closed (so you may need to repeat the last point?), then the lines should all be consistent width

You're correct 🎯 . By making the end point the same as the start point, I got

image

I was confused with what tonext should do in this case. It all makes sense now. Thanks for the clarification.

I don't think you can just say "lines are always above fills" which is what you'd need to do in order to get consistent width without duplicate edges, because if there are overlapping regions, you want the lower one covered up completely, not covering up the fill but letting the line show through.

Agreed. Asking user to repeat the starting point is better than some complex ✨ magic ✨

Another way to construct this is to make the filled traces with NO lines, then add a trace on top of them all with the lines and no fill. Then you can get away without duplicating any edges

That's an idea. That may help clear some other fill issues. Let's keep that in mind.

For now, semitransparent fills can let the gridlines shine through.

Yeah, That's fine for now.

We might make an option in layout.ternary for whether to draw gridlines above or below the data

That would be nice down the road.

@etpinard
Copy link
Contributor

@alexcjohnson OK. Let's 💃

@alexcjohnson alexcjohnson merged commit b0e7756 into master Apr 22, 2016
@alexcjohnson alexcjohnson deleted the ternary-fill branch April 22, 2016 18:59
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

Successfully merging this pull request may close these issues.

3 participants