Skip to content

scatter marker color gradients #1620

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

Merged
merged 9 commits into from
May 3, 2017
Merged

scatter marker color gradients #1620

merged 9 commits into from
May 3, 2017

Conversation

alexcjohnson
Copy link
Collaborator

  • radial, horizontal, and vertical gradients for marker fills
  • for all svg scatter types

cc @etpinard @charleyferrari - I won't be able to make changes until I'm back online mid-late week but wanted to post this for review.

- radial, horizontal, and vertical
- for all svg scatter types
// scaled by given max and min to colorscales
var markerScale = drawing.tryColorscale(marker, ''),
lineScale = drawing.tryColorscale(marker, 'line');
drawing.gradient = function(sel, gd, type, color1, color2) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was debating whether this goes in color or drawing - ended up deciding on drawing primarily because it's tied to gd (so it can create defs in the right place, without having to walk the tree with Lib.getPlotDiv for every marker) and nothing else in color is... but could be persuaded otherwise.

Copy link
Contributor

Choose a reason for hiding this comment

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

This belongs in Drawing no doubt. Color is really a lib (i.e. utility) module that shouldn't know anything about plotly attributes and especially gd.

@@ -107,7 +107,8 @@ module.exports = {
line: extendFlat({},
{width: scatterMarkerLineAttrs.width},
colorAttributes('marker'.line)
)
),
gradient: scatterMarkerAttrs.gradient
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

TODO: test image with carpet plots. Somehow imagetest isn't working for me yet with carpets, must be something I still need to update?

Copy link
Contributor

Choose a reason for hiding this comment

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

rm -rf node_modules?

Copy link
Contributor

Choose a reason for hiding this comment

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

another TODO: looks like this PR broke gl2d.

Copy link
Contributor

@rreusser rreusser Apr 24, 2017

Choose a reason for hiding this comment

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

Can you clarify which PR? Do you mean scattercarpet or this PR? Edit: realizing you probably mean these attributes need to be either added+implemented or properly avoided in gl2d.

Copy link
Contributor

Choose a reason for hiding this comment

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

This as in #1620 You can calm down @rreusser 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

scattercarpet image test in 105ce9b
gl2d fix still to come.

@@ -31,7 +38,14 @@
],
"subplot": "ternary2",
"name": "b missing",
"uid": "6c0753"
"uid": "6c0753",
Copy link
Contributor

Choose a reason for hiding this comment

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

might as well 🔪 those uid fields.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🔪 🔪 🔪 a074259

Copy link
Contributor

Choose a reason for hiding this comment

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

⤴️ commit of the year

@@ -15,12 +15,18 @@ var colorscaleDefaults = require('../../components/colorscale/defaults');

var subTypes = require('./subtypes');


/*
* opts: object of flags to control features not all marker users support
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for 🔒 ing this pattern. 🎉

* except all at once before a full redraw.
* The upside of this is arbitrary points can share gradient defs
*/
drawing.initGradients = function(gd) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice pattern. Controlling gradient defs in one place should help us in #581 too.

@@ -153,6 +153,9 @@ Plotly.plot = function(gd, data, layout, config) {
makePlotFramework(gd);
}

// clear gradient defs on each .plot call, because we know we'll loop through all traces
Drawing.initGradients(gd);
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to add jasmine test checking that restyle can update gradient defs properly.

).replace(/[^\w\-]+/g, '_');
var gradient = fullLayout._defs.select('.gradients').selectAll('#' + gradientID).data([0]);

gradient.enter()
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect this algo would work for adding gradients to bar traces? Would be a cool feature 😏

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yep, would be cool to add bar gradients... for another PR

@etpinard etpinard added this to the 1.27.0 milestone Apr 24, 2017
['radial', '#456', '#fff'],
['radial', '#456', '#eee'],
['radial', '#456', '#ddd']
]);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not happy with this... there are a bunch of ways for it to blow up in actual use, like if someone makes 1000 different gradients via different marker colors, and animates them through 1000 intermediate states, suddenly you have a million gradients lying around.

I think I need to change it to associating the gradient with the point rather than with the color combo - unless someone has another idea how to keep this in check.

else gradientColor = markerGradient.color;

var gradientID = 'g' + gd._fullLayout._uid + '-' + trace.uid;
if(perPointGradient) gradientID += '-' + i;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Now we're making either one gradient for the whole trace (if we can) or one per point (if any of the attributes varies per point) and it will update if the attributes change. This means that several traces (or several points in one trace with array attributes) will no longer be able to share a gradient def, but I don't think there are any cases where this can blow up.

Copy link
Contributor

Choose a reason for hiding this comment

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

That sounds right 👍

@@ -15,6 +15,9 @@ var Lib = require('../../lib');
// arrayOk attributes, merge them into calcdata array
module.exports = function arraysToCalcdata(cd, trace) {

// so each point knows which index it originally came from
for(var i = 0; i < cd.length; i++) cd[i].i = i;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@etpinard to my comment earlier today about not using calcdata as much: I needed to put this in because what I first tried to do, getting the index from the selection .each(d, i), is not reliable, as evidenced by the scattercarpet test image: the 0th point on the plot was actually index 1 from the trace (point 0 is cut off), but then the legend thought IT was point 0 so overwrote the other point 0 gradient.

BUT once we have that, we could get rid of the rest of these Lib.mergeArray statements - which, to address your concern earlier, don't do any sanitization anyway, we only do that for the axis data - and just directly access the arrays (if they are arrays) from within the style routines.

I'm not going to do that now, but could be a nice 🚀 at some point.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good 👁️ here and nice fix. But, I think the solution would be to make Lib.mergeArray sanatize those arrays instead of 🔪 it. We can debate this in a future issue / PR 😄

lineScale = drawing.tryColorscale(marker, 'line');
var markerScale = drawing.tryColorscale(marker, '');
var lineScale = drawing.tryColorscale(marker, 'line');
var gd = Lib.getPlotDiv(s.node());
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if it might be better to add a ref to those gradient defs in fullData[i] then to look for gd? Or even better refactor those Drawing method to expect fullLayout as argument.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll leave it for now - I agree this is suboptimal but neither of these alternatives seems particularly simpler to me. If I had to pick one I'd probably go for the first actually... stashing the <defs> in each trace could come in handy elsewhere too.

@etpinard
Copy link
Contributor

etpinard commented May 3, 2017

I'm not a big fan of that Lib.getPlotDiv call as highlighted here, but, then again, it's not that big of a deal and I'll call that non- ⛔ for 1.27.0

💃 nicely done.

@alexcjohnson alexcjohnson merged commit 2105fd4 into master May 3, 2017
@alexcjohnson alexcjohnson deleted the gradient-fill branch May 3, 2017 07:32
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