Add :mesh3d series type for Plotly (#2909)

* Add :mesh3d seriestype (in theory)

* Make it work in practice

* Clean up code

* Add support for arbitrary 3d mesh

* Add fallback for other backends

* Add shorthand

* Change i,j,k to series keyword

* Small bugfix

* Update shorthands example

* Add mesh3d example

* Add some documentation to example

* Make color work

* Move mesh3d example and add to skip list

* Update fallback recipie

* Update example

* Update src/args.jl

Co-authored-by: Simon Christ <SimonChrist@gmx.de>

* Update src/backends/plotly.jl

Co-authored-by: Simon Christ <SimonChrist@gmx.de>

* Update src/examples.jl

Co-authored-by: Simon Christ <SimonChrist@gmx.de>

* Cosmetic changes

Co-authored-by: Simon Christ <SimonChrist@gmx.de>
This commit is contained in:
Adrian Dawid 2020-08-14 14:26:16 +02:00 committed by GitHub
parent bf85afe9d6
commit e2c387894f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 9 deletions

View File

@ -38,7 +38,7 @@ const _axesAliases = Dict{Symbol,Symbol}(
) )
const _3dTypes = [ const _3dTypes = [
:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d
] ]
const _allTypes = vcat([ const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :none, :line, :path, :steppre, :steppost, :sticks, :scatter,
@ -288,6 +288,7 @@ const _series_defaults = KW(
# one logical series to be broken up (path and markers, for example) # one logical series to be broken up (path and markers, for example)
:hover => nothing, # text to display when hovering over the data points :hover => nothing, # text to display when hovering over the data points
:stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. :stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride.
:connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh
:extra_kwargs => Dict() :extra_kwargs => Dict()
) )

View File

@ -429,6 +429,7 @@ const _plotly_seriestype = [
:shape, :shape,
:scattergl, :scattergl,
:straightline, :straightline,
:mesh3d
] ]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot] const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [ const _plotly_marker = [

View File

@ -1,4 +1,3 @@
# https://plot.ly/javascript/getting-started # https://plot.ly/javascript/getting-started
is_subplot_supported(::PlotlyBackend) = true is_subplot_supported(::PlotlyBackend) = true
@ -446,7 +445,7 @@ function plotly_data(series::Series, letter::Symbol, data)
data data
end end
if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe) if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe, :mesh3d)
plotly_surface_data(series, data) plotly_surface_data(series, data)
else else
plotly_data(data) plotly_data(data)
@ -553,7 +552,7 @@ function plotly_series(plt::Plot, series::Series)
plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series) plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series)
elseif st in (:surface, :wireframe) elseif st in (:surface, :wireframe)
plotattributes_out[:type] = "surface" plotattributes_out[:type] = "surface"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
if st == :wireframe if st == :wireframe
plotattributes_out[:hidesurface] = true plotattributes_out[:hidesurface] = true
@ -572,7 +571,30 @@ function plotly_series(plt::Plot, series::Series)
end end
plotattributes_out[:showscale] = hascolorbar(sp) plotattributes_out[:showscale] = hascolorbar(sp)
end end
elseif st == :mesh3d
plotattributes_out[:type] = "mesh3d"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
if series[:connections] != nothing
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
i,j,k = series[:connections]
if !(length(i) == length(j) == length(k))
throw(ArgumentError("Argument connections must consist of equally sized arrays."))
end
plotattributes_out[:i] = i
plotattributes_out[:j] = j
plotattributes_out[:k] = k
else
throw(ArgumentError("Argument connections has to be a tuple of three arrays."))
end
end
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:color] = rgba_string(plot_color(series[:fillcolor], series[:fillalpha]))
plotattributes_out[:opacity] = series[:fillalpha]
if series[:fill_z] !== nothing
plotattributes_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
end
plotattributes_out[:showscale] = hascolorbar(sp)
else else
@warn("Plotly: seriestype $st isn't supported.") @warn("Plotly: seriestype $st isn't supported.")
return KW() return KW()

View File

@ -995,16 +995,45 @@ const _examples = PlotExample[
scatter!(Point2.(eachcol(rand(d,1000))), alpha=0.25) scatter!(Point2.(eachcol(rand(d,1000))), alpha=0.25)
end] end]
), ),
PlotExample(
"Mesh3d",
"""
Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically.
You can also specify the connections using the connections keyword. This is only supported on the Plotly backend.
The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle,
such that elements at the same position of these vectors form a triangle.
""",
[
:(
begin
# specify the vertices
x=[0, 1, 2, 0]
y=[0, 0, 1, 2]
z=[0, 2, 0, 1]
# specify the triangles
# every column is one triangle,
# where the values denote the indices of the vertices of the triangle
i=[0, 0, 0, 1]
j=[1, 2, 3, 2]
k=[2, 3, 1, 3]
# the four triangles gives above give a tetrahedron
mesh3d(x,y,z;connections=(i,j,k))
end
),
],
),
] ]
# Some constants for PlotDocs and PlotReferenceImages # Some constants for PlotDocs and PlotReferenceImages
_animation_examples = [2, 31] _animation_examples = [2, 31]
_backend_skips = Dict( _backend_skips = Dict(
:gr => [25, 30], :gr => [25, 30, 47],
:pyplot => [2, 25, 30, 31], :pyplot => [2, 25, 30, 31, 47],
:plotlyjs => [2, 21, 24, 25, 30, 31], :plotlyjs => [2, 21, 24, 25, 30, 31],
:plotly => [2, 21, 24, 25, 30, 31], :plotly => [2, 21, 24, 25, 30, 31],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30, 31, 34, 37, 38, 39], :pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30, 31, 34, 37, 38, 39, 47],
:pgfplotsx => [ :pgfplotsx => [
2, # animation 2, # animation
6, # images 6, # images
@ -1015,6 +1044,7 @@ _backend_skips = Dict(
31, # animation 31, # animation
32, # spy 32, # spy
38, # histogram2d 38, # histogram2d
47, # mesh3d
], ],
) )

View File

@ -913,6 +913,19 @@ end
@deps pie shape @deps pie shape
# ---------------------------------------------------------------------------
# mesh 3d replacement for non-plotly backends
@recipe function f(::Type{Val{:mesh3d}}, x, y, z)
# As long as no i,j,k are supplied this should work with PyPlot and GR
seriestype := :surface
if plotattributes[:connections] != nothing
throw(ArgumentError("Giving triangles using the connections argument is only supported on Plotly backend."))
end
()
end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# scatter 3d # scatter 3d
@ -928,7 +941,6 @@ end
# note: don't add dependencies because this really isn't a drop-in replacement # note: don't add dependencies because this really isn't a drop-in replacement
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# lens! - magnify a region of a plot # lens! - magnify a region of a plot
lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...) lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...)
@ -1534,3 +1546,4 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f
end end
end end
end end

View File

@ -318,6 +318,27 @@ julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
""" """
@shorthands scatter3d @shorthands scatter3d
"""
mesh3d(x,y,z)
mesh3d(x,y,z; connections)
Plot a 3d mesh. On Plotly the triangles can be specified using the connections argument.
# Example
```Julia
x=[0, 1, 2, 0]
y=[0, 0, 1, 2]
z=[0, 2, 0, 1]
i=[0, 0, 0, 1]
j=[1, 2, 3, 2]
k=[2, 3, 1, 3]
plot(x,y,z,seriestype=:mesh3d;connections=(i,j,k))
```
"""
@shorthands mesh3d
""" """
boxplot(x, y) boxplot(x, y)
boxplot!(x, y) boxplot!(x, y)