-
Notifications
You must be signed in to change notification settings - Fork 250
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
Faster Geom.point #1258
base: master
Are you sure you want to change the base?
Faster Geom.point #1258
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,34 +47,45 @@ function render(geom::PointGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics | |
Gadfly.assert_aesthetics_equal_length("Geom.point", aes, :x, :y) | ||
|
||
default_aes = Gadfly.Aesthetics() | ||
default_aes.shape = Function[Shape.circle] | ||
default_aes.color = discretize_make_ia(RGBA{Float32}[theme.default_color]) | ||
default_aes.shape = Function[theme.point_shapes[1]] | ||
default_aes.color = RGBA{Float32}[theme.default_color] | ||
default_aes.size = Measure[theme.point_size] | ||
default_aes.alpha = [theme.alphas[1]] | ||
default_aes.alpha = Float64[theme.alphas[1]] | ||
aes = inherit(aes, default_aes) | ||
|
||
if eltype(aes.size) <: Int | ||
aes_size = if eltype(aes.size) <: Int | ||
size_min, size_max = extrema(aes.size) | ||
size_range = size_max - size_min | ||
point_size_range = theme.point_size_max - theme.point_size_min | ||
interpolate_size(x) = theme.point_size_min + (x-size_min) / size_range * point_size_range | ||
theme.point_size_min .+ ((aes.size .- size_min) ./ size_range .* point_size_range) | ||
else | ||
aes.size | ||
end | ||
|
||
aes_alpha = eltype(aes.alpha) <: Int ? theme.alphas[aes.alpha] : aes.alpha | ||
|
||
aes_shape = eltype(aes.shape) <: Function ? aes.shape : theme.point_shapes[aes.shape] | ||
strokef = aes.color_key_continuous != nothing && aes.color_key_continuous ? | ||
theme.continuous_highlight_color : theme.discrete_highlight_color | ||
|
||
CT, ST, SZT, AT = eltype(aes.color), eltype(aes_shape), eltype(aes_size), eltype(aes_alpha) | ||
groups = collect(Tuple{CT, SZT, ST, AT}, Compose.cyclezip(aes.color, aes_size, aes_shape, aes_alpha)) | ||
ug = unique(groups) | ||
ctx = context() | ||
|
||
for (x, y, color, size, shape, alpha) in Compose.cyclezip(aes.x, aes.y, aes.color, aes.size, aes.shape, aes_alpha) | ||
shapefun = typeof(shape) <: Function ? shape : theme.point_shapes[shape] | ||
sizeval = typeof(size) <: Int ? interpolate_size(size) : size | ||
strokecolor = aes.color_key_continuous != nothing && aes.color_key_continuous ? | ||
theme.continuous_highlight_color(color) : | ||
theme.discrete_highlight_color(color) | ||
class = svg_color_class_from_label(aes.color_label([color])[1]) | ||
if length(groups)==1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remember thinking about this (and perhaps even testing it) but there was a reason I didn't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But julia> unique([])
0-element Array{Any,1} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An example:
For There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. am i correct in thinking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here are some stats: gp, theme = Geom.point(), Theme()
aes = Gadfly.Aesthetics()
aes.x, aes.y, aes.color = rand(1000), rand(1000), [RGB(1,0,0)]
@benchmark render($gp, $theme, $aes ) samples=10
BenchmarkTools.Trial:
memory estimate: 95.69 KiB
allocs estimate: 3129
--------------
minimum time: 128.000 μs (0.00% GC)
median time: 144.000 μs (0.00% GC)
mean time: 153.692 μs (0.00% GC)
maximum time: 246.724 μs (0.00% GC)
--------------
aes.color = fill(RGB(1,0,0), 1000)
@benchmark render($gp, $theme, $aes ) samples=10
BenchmarkTools.Trial:
memory estimate: 466.22 KiB
allocs estimate: 13195
--------------
minimum time: 2.078 ms (0.00% GC)
median time: 2.094 ms (0.00% GC)
mean time: 2.122 ms (0.00% GC)
maximum time: 2.245 ms (0.00% GC)
-------------- There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And compared to master. The timing is similar for both cases, so I only include the first case: aes.x, aes.y, aes.color = rand(1000), rand(1000), [RGB(1,0,0)]
@benchmark render($gp, $theme, $aes ) samples=10
BenchmarkTools.Trial:
memory estimate: 4.69 MiB
allocs estimate: 107096
--------------
minimum time: 6.578 ms (0.00% GC)
median time: 6.917 ms (0.00% GC)
mean time: 13.487 ms (49.08% GC)
maximum time: 60.599 ms (88.65% GC) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting. must be the my question was motivated by a desire for full SVGJS support in all cases. the following change gets that at a cost of only 15% in performance according to my benchmarking just now, a small price in my mind:
you might also consider putting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you give an example of where you would want to turn off the points in a "single-color" plot? And if you wanted to do that, why not just use case 2 above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Geom.point combined with any other Geom of a different color (density2d, ellipse, abline you name it). i don't think a small decrement in performance outweighs forcing the user to switch to a different grammer. |
||
color, size, shape, alpha = groups[1] | ||
compose!(ctx, (context(), | ||
(context(), shapefun([x], [y], [sizeval]), svgclass("marker")), | ||
fill(color), stroke(strokecolor), fillopacity(alpha), | ||
svgclass(class))) | ||
shape(aes.x, aes.y, [size]), fill(color), stroke(strokef(color)), fillopacity(alpha), | ||
svgclass("marker"))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that we should be favoring "corner cases" over speed. |
||
elseif length(groups)>1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. couldn't this just be an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i still don't understand why we need the nearly identical yet separate code blocks in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in fact, if i understand things correctly, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. got it. now i understand. |
||
for g in ug | ||
i = findall(x->isequal(x, g), groups) | ||
color, size, shape, alpha = g | ||
class = svg_color_class_from_label(aes.color_label([color])[1]) | ||
compose!(ctx, (context(), | ||
(context(), shape(view(aes.x,i), view(aes.y,i), [size]), svgclass("marker")), | ||
fill(color), stroke(strokef(color)), fillopacity(alpha), svgclass(class))) | ||
end | ||
end | ||
|
||
compose!(ctx, linewidth(theme.highlight_width)) | ||
|
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.
What was even the point of creating this function originally?
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.
Scale.size_continuous
should handle the mapping from thesize
aesthetic values to 0-1 (proportion), as for the e.g.alpha
aesthetic, so the scaling forsize
wasn't properly implemented in grammar of graphics style (unfortunately). This would be good to implement when I doGuide.sizekey
.