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

SDF strategy #5

Closed
wants to merge 41 commits into from
Closed

SDF strategy #5

wants to merge 41 commits into from

Conversation

dy
Copy link
Member

@dy dy commented Feb 3, 2017

SDF method to render fancy scatter. I reached 3e6 custom points.

Changelog

Limitations

  • Big number of big-sized points is now somewhat slower to render, hopefully it is rare case.
  • Number of available colors is limited to 256
  • Number of available characters is also limited, depending on point size

TODO

  • Render borders
  • Filter out rendering interval by boundaries
  • Make adjustable character texture size
  • Make antialias step absolute
  • Test font atlas character wrapping
  • Test various viewboxes
  • FIXMEs in code
  • Make sure no regression introduced, in particular hi-precision points, cross-browser stability, plotly.js tests
  • Add demo, elaborate readme

Some observations

  • scattergl still renders up to 1e8 points, whereas this patch is only 1e6 points. That is due to size/borderWidth/char/color buffers, it is impossible to get rid of them. We can try to patch gl-scatter2d to take color variations though. Or we can think of an alternate scatter plot with multiple render passes for different data groups. Although for big data we need special data structures, like wavelets, see ref.
  • Interactions are slower than scattergl with 1e6 points due to heavier rendering. We can try to render texture with data and re-render on update only, not during the pick.
  • Point size is off a bit (pixelRatio was the reason)
  • Colors blending is different (turned out we need special blending function)
  • Texture error
  • No point weight (need we?)

Possible optimizations

  • Cache rendered font, grouped colors etc to reduce update calculations
  • Re-render data only in update into texture, draw rendered texture in idle/pick mode

@dy
Copy link
Member Author

dy commented Feb 11, 2017

@etpinard thanks for the feedback, fixed everything except for marker displacement.
Turned out that marker is aligned a bit off inside of font itself:
image

Old gl-scatter2d-fancy aligned the point vertically regardless of font baseline etc, based on glyph shape. Here we have a hard time doing that.

One way I see is replacing marker in gl_markers from to (← see how bolder bulled is lower) and adjusting bullet size.
The other way is trying to find a font with better vertical alignment for bullet.
Also I can manually adjust offset inside of the font (ad-hoc).

@dy
Copy link
Member Author

dy commented Feb 12, 2017

@etpinard fixed everything. Turned out all marker glyphs used in plotly are shifted downwards within font, so we can safely use char offset.

The mentioned tests work alright except for point arrangement. How much is it of importance?

@etpinard
Copy link
Member

Thanks @dfcreative ! I'll give this PR another look at some point today 🎉

@etpinard
Copy link
Member

@dfcreative fantastic. I confirm that the hover picking issue of #5 (comment) is fixed ✅

In addition, the new marker offset still generate a diff in the image test, but nothing to worry about at first glance 🎉

Unfortunately, the marker.line.width computations are still off. See new diff here

image

Moreover, when generating the new baseline one after the other, it some case the axes failed to be drawn e.g. for the gl2d_10:

image

reminiscing of https://github.com/plotly/streambed/issues/6307

@dy
Copy link
Member Author

dy commented Feb 15, 2017

@etpinard yes, sorry about colors, I've merged your PR to color-id without revision - turned out we can not check like that here.
As for missing axes - could you help me reproduce that? I am facing troubles getting it, I run

const Plotly = require('plotly.js');

let list = [
	require('plotly.js/test/image/mocks/gl2d_12.json'),
	require('plotly.js/test/image/mocks/gl2d_14.json'),
	require('plotly.js/test/image/mocks/gl2d_17.json'),
	require('plotly.js/test/image/mocks/gl2d_10.json')
]

list.forEach(mock => {
	let div = document.body.appendChild(document.createElement('div'))
	Plotly.plot(div, mock.data, mock.layout).then((div) => {
		return Plotly.toImage(div).then(dataUrl => {
			let img = document.body.appendChild(document.createElement('img'))
			img.src = dataUrl
		})
	})
	.then(() => {
		Plotly.purge(div)
	})
})

and it's fine

@etpinard
Copy link
Member

yes, sorry about colors, I've merged your PR to color-id without revision - turned out we can not check like that here.

No worries! I pulled down the color-id latest changes and the marker.line.width are back to form! That is, at least in the browser, something is off in our image-test container though:

image

image

looks like the point ordering is off. But all is good in my browser window. Strange.


could you help me reproduce that? I am facing troubles getting it, I run

Try:

let list = [
	require('plotly.js/test/image/mocks/gl2d_10.json'),
	require('plotly.js/test/image/mocks/gl2d_12.json')
]

In the test dashboard, I get:

gifrecord_2017-02-15_144956

@etpinard
Copy link
Member

@dfcreative before I forgot, can you check that @monfera 's http://codepen.io/monfera/full/VmYeQb/ still works off this branch. I think that gl2d_date_axes does a good job checking for high-precision behavior, but you can't never be too sure 😄

@etpinard
Copy link
Member

... and for more info on our high-precision specs, see plotly/plotly.js#1114

@dy
Copy link
Member Author

dy commented Feb 16, 2017

@etpinard ok, fixed sorting order for small point sets and optimized @monfera's gl2d_date_axes case.
As for wrong scale of sequence of mocks — I am facing the same issue with old gl-scatter2d-fancy now, it seems to be an old symptom of some gl-plot2d problem. Trying to debug, but seems that is irrelevant to this PR.

UPD. increasing the delay here up to 3000 fixes the issue. That is the only way to get around I see for now...

@dy
Copy link
Member Author

dy commented Feb 16, 2017

@etpinard so after intense debugging I came up with this PR. It fixes the problem of wrong axes in images.

@dy
Copy link
Member Author

dy commented Feb 17, 2017

Actually mb it is better to create a separate repo, like gl-scatter2d-sdf? Changes are pretty significant, also loosing vectorizing logic completely is not too good. @etpinard

@etpinard
Copy link
Member

Actually mb it is better to create a separate repo, like gl-scatter2d-sdf?

I like this idea a lot. This will make comparing the two algorithms easier for future iterations.

loosing vectorizing logic completely is not too good

For reference, could you elaborate a little more on the drawbacks of SDF? Is there anything else worth mentioning besides what's in limitations section above?

  • Big number of big-sized points is now somewhat slower to render, hopefully it is rare case.
  • Number of available colors is limited to 256
  • Number of available characters is also limited, depending on point size

@dy
Copy link
Member Author

dy commented Feb 17, 2017

@etpinard done.
Actually I could refactor API to overcome 1e6 limitation in future and speed up updating significantly. For now we require huge arrays of repeated data, but we could group it.
Two main drawbacks I see are

  • it pre-renders canvas with font atlas, which is expected to be one-timer but potentially heavy operation (up to 100ms for some bad cases like 100+ different characters). That is avoidable by caching it.
  • it might be somewhat longer to render for cases of multiple overlapping big-sized points.

@etpinard
Copy link
Member

@dfcreative Amazing job. Here's how the baselines look like with your latest commits here and of plotly/plotly.js#1388:

https://github.com/plotly/plotly.js/compare/scattergl-sdf

Everything looks in place to me. But I wouldn't mind having someone else look at the new baselines to double check 👓

@etpinard
Copy link
Member

On second glance, looks like the bubbles in the gl2d_12 are sized slightly differently:

gifrecord_2017-02-17_135115

@dy
Copy link
Member Author

dy commented Feb 17, 2017

@etpinard yes, that is due to adjusted rendering, it looks better for the symbols.
image
vs
image
How much is that critical?

@etpinard
Copy link
Member

@dfcreative I agree, the new rendering does look better for symbols 👍

But for bubbles charts, the size of each circle has an important meaning, so the new rendering in its current form could be considered a breaking change by some.

Would it be possible to some logic for symbol: 'circle' to make them look the way they do on master?

@dy
Copy link
Member Author

dy commented Feb 18, 2017

@etpinard with gl-vis/gl-scatter2d-sdf@707658c I moved as close as I could to the initial fancy-scatter in size/border, but there are still tiny differences (1px-wise) due to method artefacts, it will be extremely difficult to remove them.

@etpinard
Copy link
Member

@dfcreative

#5 (comment)

off https://github.com/plotly/plotly.js/compare/gl-scatter2d-sdf

is looking good 🎉


Can you publish the latest changes to gl-scatter2d-sdf?

I'll take care of getting this in plotly.js master. Awesome work!

@dy
Copy link
Member Author

dy commented Feb 20, 2017

Done https://www.npmjs.com/package/gl-scatter2d-sdf. Thank you!

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

Successfully merging this pull request may close these issues.

None yet

2 participants