-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
3D streamtube traces #2658
3D streamtube traces #2658
Conversation
- reuse cone colorbar - compute x/y/z bounds in calc - pass cmin/cmax to meshData.vertexIntensityBounds - rename starting position attributes cx/cy/cz -> startx/starty/startz - misc cleanup to bring streamtube closer to cone - add new TODOs
Update: Here's a few problems I noticed yesterday:
From 812be20#r29129877, On-par with As for hover, it's an interesting problem. I'm thinking of three families of solution. 1) Just show the vector field x/y/z and u/v/w pt values just like for cones. This solution is true to the input data, but doesn't offer info about the tubes. 2) Just show the coordinates of the tubes' vertices and the u/v/w components at their location. Here, we're entirely in "tube-space", the input x/y/z and u/v/w don't show up on hover. 3) Show the tubes' starting position (i.e. items from Thoughts? |
"True to the data" is my preference here - it shows you a bit of what you've missed about the data by converting to tubes. It shouldn't often be very far off the interpolated values, right?
Interesting indeed - I actually think "true to the data" would be really confusing here, as there's nothing to "hover on" at the data point. Particularly since this is 3D, you could end up hovering on something at a totally different depth from the tube you're inspecting. The tube vertices (2) don't mean anything. I assume when you say this you're talking about the surface of the tube? I'm thinking the ideal solution (tell me how painful this would be to calculate...) would be to find the exact tube surface point the cursor is over (not the closest vertex) and project from there back to the centerline of the tube; show x/y/z and u/v/w/norm for that point (or perhaps the closest actual data point? that could be confusing though); and perhaps somehow highlight the whole tube, so you can see not just where it came from but the whole streamline? That last part seems more like a "nice to have" that we could add later though. |
Fantastic 👌
Yes, exactly.
I agree, this sounds like ideal. I'll have to dig into how the tubes coordinates are computed to answer the "how painful this would be" question. Maybe @kig would be interested in helping us out? |
The streamtube visualization needs a continuous vector field. It works by sampling the vector field at each of the starting points, then moving a small amount along the sampled vector, sampling again, moving again, repeat until far enough from the starting point to create a stream segment. Push stream segment to the stream points array, continue until out of bounds or reach maxLength segments in stream points array. The meshgrid parameter defines the vector field for the streamtubes. It maps each of the vectors to a position in space. And since it's a nicely defined grid, it's easy to sample values inside each grid cell by interpolating between the 8 corners of the cell according to the sample position. Doing arbitrary vector positions for the vector field would be doable if you've got some nice algorithm to sample them as a continuous vector field. Re: widthScale, auto scale, I wrote an auto scaler this morning. gl-vis/gl-streamtube3d@97c89d7 -- it also removes the widthScale parameter and replaces it with tubeSize and absoluteTubeSize params. The auto scaler keeps track of the maximum divergence value encountered and uses that to calculate the radius of the tubes. The tubeSize param controls the auto scaled width so that tubeSize of 1 would scale two max divergence tubes at adjacent starting positions so that they don't overlap. The absoluteTubeSize param overrides the auto scaler, and is used to multiply the divergence value to get the tube radius in coordinate space units. The divergence used for the streamtubes is || divF || instead of the divF 3-vector. I don't know if that's the right thing to do or if we should scale the tubes in a non-uniform fashion according to the 3D divergence.
This sounds doable, the tubes definition contains all the sampled interpolated data points, and picking should get you the triangle & data point matching that. What would you need for this? |
Thanks @kig ! I'll try to incorporate your work in this PR in the next few hours. |
... using @kig's work from gl-vis/gl-streamtube3d#3
Thanks for writing this down @kig . You're absolutely right, the "mesh" requirements for streamtubes are much more stringent than for cones. Too bad x/y/z will have a slightly different meaning in Having x/y/z generate of "mesh" of var x = [], y = [], z = [];
var u = [], v = [], w = [];
for(var i = 0; i < nx; i++) {
for(var j = 0; j < ny; j++) {
for(var k = 0; k < nz; k++) {
x.push(i); y.push(j); z.push(k);
u.push(1+Math.sin(i));
v.push(Math.cos(j));
w.push(Math.sin(k*0.3)*0.3);
}
}
} |
It's not way less efficient - x/y/z are way bigger, but the trace as a whole is only twice as big. I think we should require this form (x/y/z/u/v/w all the same length) as the default. We can extend this with some non-default option that lets users specify the more efficient x/y/z (either with 3D or 1D u/v/w arrays, we can discuss that later), but then we can also handle arbitrary sample points in the future, either by pre-interpolating like in convert_column_xyz and interp2d or some Delaunay-like algorithm. And it'll ensure users can switch between |
This is winning argument 🏆 . @kig would you be interested in converting the |
By converting the meshgrid argument to x/y/z positions, do you mean that it'd be like an "expanded" meshgrid? You'd have the same x coordinates for every y and the same y coords for every z, and they'd be sorted small to big? For example,
|
Btw the cone meshgrid argument works in a similar fashion. It interprets the vector array as a vector field, and then uses the cone positions as points to sample from the vector field. |
... with the help of gl-vis/gl-streamtube3d#5
- which makes x/y/z and u/v/w streamtube data interchangeable with cone traces - convert x/y/z columns to gl-streamtube "meshgrid" using Lib.distinctVals - add pad around tube x/y/z bounds to allow them to go a little bit beyond the mesh w/o getting clipped.
Yes, exactly. Commit e99ffc9 adds a x/y/z columns -> meshgrid vector converter in plotly.js before calling
We chose to not expose gl-cone3d's "meshgrid" setting to plotly.js users in 5a42de0. In this context, (if I understand correctly), gl-cone3d assumes that the x/y/z |
cc @kig
|
src/traces/streamtube/convert.js
Outdated
} else { | ||
// use all pts on 2x2 and 1x1 planes | ||
sx = valsx.slice(); | ||
sz = valsz.slice(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably this length > 2
condition should be done separately for x and z? Also, I don't know what model is used for extending the field outside the x/y/z bounds, but if it's uncertain enough that at 3+ points it's best not to start at the last coordinate, then I'd think at 2 points it'd be best to use a single point halfway between the two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I don't know what model is used for extending the field outside the x/y/z bounds
Currently, positions outside the mesh get (u=0, v=0, w=0) if I understand correctly:
cc @kig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New attempt in 83f3bdc
// Does not correspond to input x/y/z, so delete them | ||
delete out.x; | ||
delete out.y; | ||
delete out.z; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🍰
This could be done in a post processing pass, checking if any two points have a distance below an epsilon -> throw away the shorter stream suffix. As it is, the stream generator just generates a stream from each starting point and draws them all out. |
- to not have to .slice input array twice
... mesh3d, surface and streamtube attribute declarations.
@alexcjohnson are any of your remarks in #2658 (comment) blocking for a v1 release? @kig would you be interested in looking at the broken tube @alexcjohnson noticed in |
extendFlat(attrs, colorAttrs('', 'calc', true), { | ||
showscale: colorscaleAttrs.showscale, | ||
extendFlat(attrs, colorscaleAttrs('', { | ||
colorAttr: 'u/v/w norm', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This give better attribute descriptions for cone colorscale
and friends. For example, for cmin
we have
"Sets the lower bound of the color domain. Value should have the same units as the u/v/w norm and if set,
cmax
must be set as well."
Just the broken tube - if there's a benign explanation for it then fine, I'd just like us to make sure we're not setting ourselves up for breaks in some broad class of conditions we haven't fully explored yet. |
More on the broken tube of #2658 (comment), At which looks like one (very) narrow but not broken section. the same view at where many tubes are overlapping. |
Right, two ideas of what might be causing this. The coordinate system generated based on the velocity vector is not continuous, so when a stream passes through a discontinuous angle, the coordinate axes suddenly change, which would cause a >< kink in the tube. Alternative explanation: the divergence function returns a zero for some reason. |
Ok merging this thing. Go to #2781 for a list of open items. |
Yeah, that's probably what happens. At some angles, the coordinate system generated from only the velocity vector suddenly swaps its axes. I can fix it by also sending the previous velocity vector, then the shader could compare the coordinate systems to avoid sudden swaps. Or do it in JS and pass up vectors to the shader. |
Note that this branch is @kig 's https://github.com/plotly/plotly.js/tree/gl-vis-streamtube rebased with the 2018/05/28 master.
Streamtubes are coming to plotly.js, this time for real (#701 😏 )
But first, we'll need to bring this branch up-to-speed with the work done for cones in #2641 ⚒️
Here's a list of TODOs:
gl-streamtube3d
iteration allows users to define starting positions, would that be enough for the v1?812be20#r29119106
streamtubes
as in fa32a74tubeScale
cone
tracesbounds
isn't a per-trace setting in plotly.jsmaxLength
doeswidthScale
does (would usingsizeref
in plotly.js like for cones be ok?)cone/calc.js
andcone/colorbar.js
here)gl-streamtube3d
to npm and update package.json depcc @alexcjohnson @jackparmer @kig