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

Introducing splom traces #2505

Merged
merged 108 commits into from
Apr 16, 2018
Merged

Introducing splom traces #2505

merged 108 commits into from
Apr 16, 2018

Conversation

etpinard
Copy link
Contributor

@etpinard etpinard commented Mar 28, 2018

resolves #2372

This is a feature branch built off PRs #2474, #2487, #2492 and #2499 where all splom development should start off from. Other splom-related branches on origin like splom and splom-dev are now obsolete.

cc @dfcreative @alexcjohnson

@etpinard
Copy link
Contributor Author

etpinard commented Mar 28, 2018

As of the commit fda1b34,

things that work

  • splom markers thanks to https://github.com/dfcreative/regl-scattermatrix and their styling thanks to 1c6144e (I haven't tested arrayOk attributes though)
  • zoom and drag
  • graph with multiple splom traces
  • splom traces that generate layout.grid
  • splom traces that default their corresponding axis title
  • is pretty fast (more on that soon)

things that do not work

  • ✅ image generation in nw.js (that's why the new splom mock don't have corresponding baselines). Note that image generation via the modebar button appear to work fine. (etienne)
  • ✅ something is off with splom + other cartesian trace types (etienne)
  • ✅ hover (dima)
  • ✅ selection (dima)
  • ✅ legend items styling
  • mode: 'lines' defer to next iteration
  • ✅ splom attributes xdirection, ydirection, showdiagonal, showupperhalf showlowerhalf (or shouldn't that be a flaglist by the way 🤔 )
  • regl-line2d grid line updates (fixed, but could be cleaned up)
  • ✅ test out marker options
  • ✅ non-linear axes!
  • tests !
  • probably more things I can't think about right now

✅ means works now I think.


Here's what the splom_iris mock looks like:

peek 2018-03-27 22-58

@@ -486,7 +486,7 @@ function getLayoutAttributes() {

if(!_module.layoutAttributes) continue;

if(_module.name === 'cartesian') {
if(_module.name === 'cartesian' || _module.name === 'splom') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we do this just based on _module.attr?
if(Array.isArray(_module.attr)) { _module.attr.forEach(... handleBasePlotModule) }

Copy link
Contributor Author

@etpinard etpinard Mar 30, 2018

Choose a reason for hiding this comment

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

done in 9162265

role: 'info',
editType: 'plot',
description: ''
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

layout.grid doesn't have an analog of xdirection, do we need that? And in place of ydirection we have roworder: ('top to bottom'|'bottom to top') which feels clearer to me than ('top'|'bottom'). Actually I wonder if these belong in splom attributes at all, or if we should just let layout.grid handle it. It's nice for the simple single-trace case, but once you get two splom traces, seems like only one (the first?) matters, so having one in each trace would be confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I wonder if these belong in splom attributes at all, or if we should just let layout.grid handle it. It's nice for the simple single-trace case, but once you get two splom traces, seems like only one (the first?) matters, so having one in each trace would be confusing.

I agree 100% here. I'm thinking of 🔪 ing xdirection and ydirection. Users won't have a way to plot their splom dimensions from right to left until layout.grid.columnorder is implemented, but I don't think that's a big deal. Any objections?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🔪 in a077c3f

dflt: true,
editType: 'plot',
description: ''
},
Copy link
Collaborator

@alexcjohnson alexcjohnson Mar 28, 2018

Choose a reason for hiding this comment

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

Eventually we will want the diagonals to support various types: scattergl, histogram, box, violin. So I'm wondering if instead of showdiagonal we should have diagonal: {visible: (true|false)} to support future expansion:

diagonal: {
    visible: (true|false),
    type: (scattergl|histogram|box|violin),
    // then attributes specific to each type, as well as some overrides per dimension
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Eventually we will want the diagonals to support various types: scattergl, histogram, box, violin.

Interesting. So you're thinking a single splom trace could generate scatter panels AND histogram or box or violin traces on the diagonal? That would put us on-par with some of the seaborn. Yeah nice. I can't really think of any drawbacks from that approach except this might cause headaches to the workspace team.

Copy link
Collaborator

Choose a reason for hiding this comment

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

a single splom trace could generate scatter panels AND histogram or box or violin traces on the diagonal?

Yes exactly. An extra complication is that this would create even more x or y axes (for the histogram count or box/violin category), depending on the type and orientation of these diagonal plots; but once we do that, it seems like the implementation should be fairly straightforward. But anyway none of that has to happen now, as long as we set up the attributes we DO need now so they'll support this.

Choose a reason for hiding this comment

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

hi @alexcjohnson, i'm really interested to use the diagonal type. Is it available to use?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Currently the diagonal can only have scatter type. Follow #2555 for more info, but we do not have any immediate plans for when other types will be added.

Choose a reason for hiding this comment

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

oh okay. Thanks

dflt: true,
editType: 'plot',
description: ''
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we get rid of showdiagonal I'm not sure it makes sense to turn these two into a little flaglist - perhaps just leave them as two booleans.

var handleMarkerDefaults = require('../scatter/marker_defaults');
var handleLineDefaults = require('../scatter/line_defaults');
var PTS_LINESONLY = require('../scatter/constants').PTS_LINESONLY;
var OPEN_RE = /-open/;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, going to break for symbol numbers

Copy link
Contributor Author

Choose a reason for hiding this comment

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

-> move to #2507 thanks!

var xaxes = coerce('xaxes', xaxesDflt);
var yaxes = coerce('yaxes', yaxesDflt);

// TODO what to do when xaxes.length or yaxes.length !== dimLength ???
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess if dimLength is longer it's easy to just drop the later dims. What if xaxes.length !== yaxes.length or dimLength is shorter than xaxes or yaxes? The easy thing to do is just truncate them all to the same length, and perhaps until we have a clear use case otherwise we should just do that.

Related though: if you have several splom traces but they don't share all the same dimensions, you could of course handle this by specifying xaxes and yaxes for each, but could you also just pass in an empty dimension for ones you want to skip? If that takes more than 5 minutes to implement though, skip it for now and leave it as an item for future expansion.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh you already have dimensions[i].visible: false, nice! That should take care of my "related" point, it'll still reserve x/y axes for these dimensions, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The easy thing to do is just truncate them all to the same length, and perhaps until we have a clear use case otherwise we should just do that.

That sounds right to me. I'll go with that unless anyone disagrees.

That should take care of my "related" point, it'll still reserve x/y axes for these dimensions, right?

Yes that should take care of it, but I haven't tried that yet. Putting that on my TODO list 📝

Copy link
Contributor Author

@etpinard etpinard Mar 28, 2018

Choose a reason for hiding this comment

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

.... thanks for all these comments by the way. I hope you don't find the _hasOnlyLargeSplom flag too hacky.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alexcjohnson just to confirm what you meant in your related point:

Plotly.newPlot(gd, [{
  type: 'splom',
  dimensions: [{
    values: [1, 2, 3]
  }, {
    values: [4, 5, 6]
  }]
}, {
  type: 'splom',
  dimensions: [{
    visible: false
  }, {
    visible: false,
  }, {
    values: [1, 2, 3]
  }, {
    values: [4, 5, 6]
  }]
}])

gives:

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in 07d59d5

@@ -691,7 +691,6 @@
"layout": {
"title": "Iris dataset splom",
"width": 600,
"height": 500,
"showlegend": false
"height": 500
Copy link
Contributor Author

Choose a reason for hiding this comment

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

first cut baselines 🎉

cc @dfcreative

Copy link
Contributor Author

Choose a reason for hiding this comment

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

... notice how the legend items aren't showing the correct symbol. Fixing that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ignore last comment. Something else fixed that.

@etpinard
Copy link
Contributor Author

Here's what happens with when allowing cross-subplot selections (like we have currently on master):

peek 2018-04-12 11-46

Three things to notice:

  • the event data pointNumber values correspond to the pt indices in every dimensions[i].values. I think that's correct. Attribute selectedpoints follows the same rule.
  • the selection outlines do not match the selected points when selecting across subplots.
  • multi-select works per subplot, trying to multi-select across subplot doesn't work at the moment.

With commits 71a0395 and 9d0bcfd we have a slightly more consistent (albeit incomplete) behavior:

peek 2018-04-12 11-50

In brief, with these commits:

  • we clear selection outlines when selecting in a different subplot than the previous selection
  • we disallow multi-select across subplots

'geo',
'pie',
'ternary'
]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

great test!

@etpinard
Copy link
Contributor Author

etpinard commented Apr 12, 2018

with commit a79f5dc splom interactions are now 🔒ed , I'll tag this PR as reviewable.

So, here's an updated pre-merge checklist:

  • maybe tweak some test values for CI
  • approval from @alexcjohnson
  • test @dy regl-line2d update
  • adapt _splomGrid code for new regl-line2d (if necessary)
  • release / publish new versions of regl-scattermatrix, regl-scatter2d and regl-line2d
  • update package.json and package-lock.json
  • write down first-render time table (10 dims / 20k values, 20/5k, 30/2k, 40/1k, 50/800)

Note that I just made two comments:

arguing for leaving some previous unaddressed in this PR.

@alexcjohnson
Copy link
Collaborator

As long as all the TODOs added here are linked to the upcoming splom open items issue(s) I agree, they're all fine to omit from this PR. Looking amazing guys! 💃

@etpinard etpinard mentioned this pull request Apr 13, 2018
7 tasks
@etpinard
Copy link
Contributor Author

Here are some first-render benchmarks with showupperhalf: false and diagonal.visible: false:

# of dimensions # of values per dimension regl-line2d grid lines? time [ms]
10 20k no 400-500
20 5k yes 600-700
30 2k yes 900-1000
40 1k yes 1300-1400
50 800 yes 2000-2300

computed using:

var Nvars = /* fill this in */
var Nrows = /* fill this in */
var dims = []

for(var i = 0; i < Nvars; i++) {
  dims.push({values: []})
  
  for(var j = 0; j < Nrows; j++) {
     dims[i].values.push(Math.random())
  }
}

Plotly.purge(gd);

console.time('splom')
Plotly.newPlot(gd, [{
  type: 'splom',
  dimensions: dims,
  showupperhalf: false,
  diagonal: {visible: false},
}], {width: 2000, height: 2000})
console.timeEnd('splom')

@etpinard
Copy link
Contributor Author

Merging this thing!

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

Successfully merging this pull request may close these issues.

Scatter Plot Matrix (aka SPLOM) discussion
5 participants