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

First attempt at histogram3d/legoplot #3507

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/args.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ const _axesAliases = Dict{Symbol,Symbol}(
)

const _3dTypes = [
:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d
:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d, :histogram3d
]
const _allTypes = vcat([
:none, :line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins,
:scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d,
:scatterhist, :stepbins, :stephist, :bins2d, :histogram2d,
:density, :bar, :hline, :vline,
:contour, :pie, :shape, :image
], _3dTypes)
Expand Down Expand Up @@ -94,13 +94,15 @@ const _typeAliases = Dict{Symbol,Symbol}(
:imagesc => :image,
:hist => :histogram,
:hist2d => :histogram2d,
:hist3d => :histogram3d,
:lego => :histogram3d,
:bezier => :curves,
:bezier_curves => :curves,
)

add_non_underscore_aliases!(_typeAliases)

const _histogram_like = [:histogram, :barhist, :barbins]
const _histogram_like = [:histogram, :barhist, :barbins, :histogram3d]
const _line_like = [:line, :path, :steppre, :stepmid, :steppost]
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]

Expand Down
2 changes: 1 addition & 1 deletion src/axes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ function widen(lmin, lmax, scale = :identity)
end

# figure out if widening is a good idea.
const _widen_seriestypes = (:line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d)
const _widen_seriestypes = (:line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d, :histogram3d)

function default_should_widen(axis::Axis)
should_widen = false
Expand Down
114 changes: 113 additions & 1 deletion src/recipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,118 @@ end
end


# ---------------------------------------------------------------------------
# Histogram 3D

# Check if all neighbours have the same value
# TODO: Improve this somehow
function _allneighbours(arr, I::CartesianIndex, val = 0.0)
arr[I] == val &&
arr[I + CartesianIndex(1,0)] == val &&
arr[I + CartesianIndex(0,1)] == val &&
arr[I - CartesianIndex(1,0)] == val &&
arr[I - CartesianIndex(0,1)] == val &&
arr[I + CartesianIndex(1,1)] == val &&
arr[I + CartesianIndex(1,-1)] == val &&
arr[I - CartesianIndex(1,1)] == val &&
arr[I - CartesianIndex(1,-1)] == val
end

@recipe function f(::Type{Val{:bins3d}}, x, y, z)
edge_x, edge_y, weights = x, y, z.surf

# Create the bins
if !plotattributes[:show_empty_bins]
edge_x = repeat(edge_x,inner=(4))[2:end-1]
edge_y = repeat(edge_y,inner=(4))[2:end-1]
float_weights = spzeros(length(edge_x),length(edge_y))
float_weights[2:end-1,2:end-1] = repeat(float(weights),inner=(4,4))
m = falses(size(float_weights))
for I in CartesianIndices((2:length(edge_x)-1,2:length(edge_y)-1))
m[I] = _allneighbours(float_weights,I,0)
end
float_weights[m] .= NaN
else
edge_x = repeat(edge_x,inner=(2))
edge_y = repeat(edge_y,inner=(2))
float_weights = spzeros(length(edge_x),length(edge_y))
float_weights[2:end-1,2:end-1] .= repeat(float(weights),inner=(2,2))
end

# pyplot can't handle sparse arrays it seems
# Maybe get rid off sparse arrays at all, but if any bins-entry is large the additional points for plotting may use up a lot of memory otherwise for zeros and NaNs
if backend_name() == :pyplot
float_weights = Surface(permutedims(Array(float_weights)))
else
float_weights = Surface(permutedims(float_weights))
end

# Handle input of one seriescolor only (maybe exchangeable by get_series_color()?)
if isa(plotattributes[:seriescolor], Symbol) && plotattributes[:seriescolor] != :auto
seriescolor := cgrad([plotattributes[:seriescolor], plotattributes[:seriescolor]])
end

seriestype := :surface
colorbar := false
x := edge_x
y := edge_y
z := float_weights

()
end
Plots.@deps bins3d surface #wireframe mesh3d



@recipe function f(::Type{Val{:bricks3d}}, x, y, z)
edge_x, edge_y, weights = x, y, z.surf

x_step = edge_x[2] - edge_x[1]
y_step = edge_y[2] - edge_y[1]
x_len = length(x)
y_len = length(y)

temp_x = vec([0.0 0.0 1.0 1.0]).*x_step .+ edge_x'
temp_y = vec([1.0 1.0 0.0 0.0]).*y_step .+ edge_y'

z_help = [1.0 0.0 0.0 1.0;
0.0 1.0 1.0 0.0;
0.0 1.0 1.0 0.0;
1.0 0.0 0.0 1.0];

for (i, c) in enumerate(weights)
itx = (i-1)%y_len + 1
ity = floor(Int64,i/x_len) + 1
@series begin
seriestype := :surface
x := temp_x[:,itx]
y := temp_y[:,ity]
z := c == 0 ? Surface(permutedims(NaN .* z_help)) : Surface(permutedims(c .* z_help))
()
end
end


end
Plots.@deps bins3d surface #wireframe mesh3d


@recipe function f(::Type{Val{:histogram3d}}, x, y, z)
h = _make_hist(
(x, y),
plotattributes[:bins],
normed = plotattributes[:normalize],
weights = plotattributes[:weights],
)
x := h.edges[1]
y := h.edges[2]
z := Surface(h.weights)
seriestype := :bricks3d#:bins3d
()
end
@deps histogram3d bins3d bricks3d


# ---------------------------------------------------------------------------
# pie
@recipe function f(::Type{Val{:pie}}, x, y, z)
Expand Down Expand Up @@ -1430,7 +1542,7 @@ end

@recipe function f(shapes::AVec{Shape})
seriestype --> :shape
# For backwards compatibility, column vectors of segmenting attributes are
# For backwards compatibility, column vectors of segmenting attributes are
# interpreted as having one element per shape
for attr in union(_segmenting_array_attributes, _segmenting_vector_attributes)
v = get(plotattributes, attr, nothing)
Expand Down
20 changes: 20 additions & 0 deletions src/shorthands.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ julia> histogram2d(randn(10_000),randn(10_000))
"""
@shorthands histogram2d

"""
histogram3d(x,y)
histogram3d!(x,y)

Plot a three-dimensional histogram.

# Arguments

- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
its weight to the height of its bin.

# Example
```julia-repl
julia> histogram3d(randn(10_000),randn(10_000))
```
"""
@shorthands histogram3d
@shorthands legoplot

"""
density(x)
density!(x)
Expand Down
1 change: 1 addition & 0 deletions src/subplots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function should_add_to_legend(series::Series)
:hexbin,
:bins2d,
:histogram2d,
:histogram3d,
:hline,
:vline,
:contour,
Expand Down