diff --git a/src/args.jl b/src/args.jl index 58f4464e..f5a8887a 100644 --- a/src/args.jl +++ b/src/args.jl @@ -38,7 +38,7 @@ const _axesAliases = Dict{Symbol,Symbol}( ) const _3dTypes = [ - :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume + :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d ] const _allTypes = vcat([ :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) :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. + :connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh :extra_kwargs => Dict() ) diff --git a/src/backends.jl b/src/backends.jl index 6d586358..cb92d98c 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -429,6 +429,7 @@ const _plotly_seriestype = [ :shape, :scattergl, :straightline, + :mesh3d ] const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot] const _plotly_marker = [ diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index eedcc5fe..9f4a3a9f 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -1,4 +1,3 @@ - # https://plot.ly/javascript/getting-started is_subplot_supported(::PlotlyBackend) = true @@ -446,7 +445,7 @@ function plotly_data(series::Series, letter::Symbol, data) data end - if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe) + if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe, :mesh3d) plotly_surface_data(series, data) else plotly_data(data) @@ -553,7 +552,7 @@ function plotly_series(plt::Plot, series::Series) plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series) 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 if st == :wireframe plotattributes_out[:hidesurface] = true @@ -572,7 +571,30 @@ function plotly_series(plt::Plot, series::Series) end plotattributes_out[:showscale] = hascolorbar(sp) 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 @warn("Plotly: seriestype $st isn't supported.") return KW() diff --git a/src/examples.jl b/src/examples.jl index 814083c2..88ee8c9c 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -995,16 +995,45 @@ const _examples = PlotExample[ scatter!(Point2.(eachcol(rand(d,1000))), alpha=0.25) 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 _animation_examples = [2, 31] _backend_skips = Dict( - :gr => [25, 30], - :pyplot => [2, 25, 30, 31], + :gr => [25, 30, 47], + :pyplot => [2, 25, 30, 31, 47], :plotlyjs => [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 => [ 2, # animation 6, # images @@ -1015,6 +1044,7 @@ _backend_skips = Dict( 31, # animation 32, # spy 38, # histogram2d + 47, # mesh3d ], ) diff --git a/src/recipes.jl b/src/recipes.jl index cfcb9390..14beefac 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -913,6 +913,19 @@ end @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 @@ -928,7 +941,6 @@ end # note: don't add dependencies because this really isn't a drop-in replacement - # --------------------------------------------------------------------------- # lens! - magnify a region of a plot 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 + diff --git a/src/shorthands.jl b/src/shorthands.jl index 63bec003..7b9584c9 100644 --- a/src/shorthands.jl +++ b/src/shorthands.jl @@ -318,6 +318,27 @@ julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27]) """ @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)