working on GR; series_list and should_add_to_legend; series recipes fix; hist and bar recipes
This commit is contained in:
parent
603dc30bb1
commit
dae9dad2f7
25
src/args.jl
25
src/args.jl
@ -232,13 +232,14 @@ const _axis_defaults = KW(
|
|||||||
:foreground_color_guide => :match, # guide text color,
|
:foreground_color_guide => :match, # guide text color,
|
||||||
)
|
)
|
||||||
|
|
||||||
const _suppress_warnings = KW(
|
const _suppress_warnings = Set{Symbol}([
|
||||||
:x_discrete_indices => nothing,
|
:x_discrete_indices,
|
||||||
:y_discrete_indices => nothing,
|
:y_discrete_indices,
|
||||||
:z_discrete_indices => nothing,
|
:z_discrete_indices,
|
||||||
:subplot => nothing,
|
:subplot,
|
||||||
:subplot_index => nothing,
|
:subplot_index,
|
||||||
)
|
:series_plotindex,
|
||||||
|
])
|
||||||
|
|
||||||
# add defaults for the letter versions
|
# add defaults for the letter versions
|
||||||
const _axis_defaults_byletter = KW()
|
const _axis_defaults_byletter = KW()
|
||||||
@ -433,9 +434,7 @@ function default(k::Symbol)
|
|||||||
return defaults[k]
|
return defaults[k]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if !haskey(_suppress_warnings, k)
|
k in _suppress_warnings || error("Unknown key: ", k)
|
||||||
error("Unknown key: ", k)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function default(k::Symbol, v)
|
function default(k::Symbol, v)
|
||||||
@ -446,9 +445,7 @@ function default(k::Symbol, v)
|
|||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if !haskey(_suppress_warnings, k)
|
k in _suppress_warnings || error("Unknown key: ", k)
|
||||||
error("Unknown key: ", k)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function default(; kw...)
|
function default(; kw...)
|
||||||
@ -789,7 +786,7 @@ end
|
|||||||
function warnOnUnsupportedArgs(pkg::AbstractBackend, d::KW)
|
function warnOnUnsupportedArgs(pkg::AbstractBackend, d::KW)
|
||||||
for k in sortedkeys(d)
|
for k in sortedkeys(d)
|
||||||
k in supportedArgs(pkg) && continue
|
k in supportedArgs(pkg) && continue
|
||||||
haskey(_suppress_warnings, k) && continue
|
k in _suppress_warnings && continue
|
||||||
if d[k] != default(k)
|
if d[k] != default(k)
|
||||||
warn("Keyword argument $k not supported with $pkg. Choose from: $(supportedArgs(pkg))")
|
warn("Keyword argument $k not supported with $pkg. Choose from: $(supportedArgs(pkg))")
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1127,13 +1127,16 @@ function addPyPlotLegend(plt::Plot, sp::Subplot, ax)
|
|||||||
# gotta do this to ensure both axes are included
|
# gotta do this to ensure both axes are included
|
||||||
labels = []
|
labels = []
|
||||||
handles = []
|
handles = []
|
||||||
for series in plt.series_list
|
# for series in plt.series_list
|
||||||
if get_subplot(series) === sp &&
|
# if get_subplot(series) === sp &&
|
||||||
series.d[:label] != "" &&
|
# series.d[:label] != "" &&
|
||||||
!(series.d[:seriestype] in (
|
# !(series.d[:seriestype] in (
|
||||||
:hexbin,:hist2d,:hline,:vline,
|
# :hexbin,:hist2d,:hline,:vline,
|
||||||
:contour,:contour3d,:surface,:wireframe,
|
# :contour,:contour3d,:surface,:wireframe,
|
||||||
:heatmap,:path3d,:scatter3d, :pie, :image))
|
# :heatmap,:path3d,:scatter3d, :pie, :image))
|
||||||
|
for series in series_list(sp)
|
||||||
|
if should_add_to_legend(series)
|
||||||
|
# add a line/marker and a label
|
||||||
push!(handles, if series.d[:seriestype] == :hist
|
push!(handles, if series.d[:seriestype] == :hist
|
||||||
PyPlot.plt[:Line2D]((0,1),(0,0), color=pyfillcolor(series.d), linewidth=4)
|
PyPlot.plt[:Line2D]((0,1),(0,0), color=pyfillcolor(series.d), linewidth=4)
|
||||||
else
|
else
|
||||||
@ -1142,6 +1145,8 @@ function addPyPlotLegend(plt::Plot, sp::Subplot, ax)
|
|||||||
push!(labels, series.d[:label])
|
push!(labels, series.d[:label])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# if anything was added, call ax.legend and set the colors
|
||||||
if !isempty(handles)
|
if !isempty(handles)
|
||||||
leg = ax[:legend](handles,
|
leg = ax[:legend](handles,
|
||||||
labels,
|
labels,
|
||||||
|
|||||||
@ -20,11 +20,11 @@ function _create_backend_figure(plt::Plot{[PkgName]Backend})
|
|||||||
end
|
end
|
||||||
|
|
||||||
# this is called early in the pipeline, use it to make the plot current or something
|
# this is called early in the pipeline, use it to make the plot current or something
|
||||||
function _prepare_plot_object(plt::Plot{[PkgName]})
|
function _prepare_plot_object(plt::Plot{[PkgName]Backend})
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set up the subplot within the backend object.
|
# Set up the subplot within the backend object.
|
||||||
function _initialize_subplot(plt::Plot{PyPlotBackend}, sp::Subplot{PyPlotBackend})
|
function _initialize_subplot(plt::Plot{[PkgName]Backend}, sp::Subplot{[PkgName]Backend})
|
||||||
end
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@ -42,7 +42,7 @@ end
|
|||||||
|
|
||||||
# called just before updating layout bounding boxes... in case you need to prep
|
# called just before updating layout bounding boxes... in case you need to prep
|
||||||
# for the calcs
|
# for the calcs
|
||||||
function _before_layout_calcs(plt::Plot)
|
function _before_layout_calcs(plt::Plot{[PkgName]Backend})
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
defaultOutputFormat(plt::AbstractPlot) = "png"
|
defaultOutputFormat(plt::Plot) = "png"
|
||||||
|
|
||||||
function png(plt::AbstractPlot, fn::@compat(AbstractString))
|
function png(plt::Plot, fn::@compat(AbstractString))
|
||||||
fn = addExtension(fn, "png")
|
fn = addExtension(fn, "png")
|
||||||
io = open(fn, "w")
|
io = open(fn, "w")
|
||||||
writemime(io, MIME("image/png"), plt)
|
writemime(io, MIME("image/png"), plt)
|
||||||
@ -10,7 +10,7 @@ function png(plt::AbstractPlot, fn::@compat(AbstractString))
|
|||||||
end
|
end
|
||||||
png(fn::@compat(AbstractString)) = png(current(), fn)
|
png(fn::@compat(AbstractString)) = png(current(), fn)
|
||||||
|
|
||||||
function svg(plt::AbstractPlot, fn::@compat(AbstractString))
|
function svg(plt::Plot, fn::@compat(AbstractString))
|
||||||
fn = addExtension(fn, "svg")
|
fn = addExtension(fn, "svg")
|
||||||
io = open(fn, "w")
|
io = open(fn, "w")
|
||||||
writemime(io, MIME("image/svg+xml"), plt)
|
writemime(io, MIME("image/svg+xml"), plt)
|
||||||
@ -19,7 +19,7 @@ end
|
|||||||
svg(fn::@compat(AbstractString)) = svg(current(), fn)
|
svg(fn::@compat(AbstractString)) = svg(current(), fn)
|
||||||
|
|
||||||
|
|
||||||
function pdf(plt::AbstractPlot, fn::@compat(AbstractString))
|
function pdf(plt::Plot, fn::@compat(AbstractString))
|
||||||
fn = addExtension(fn, "pdf")
|
fn = addExtension(fn, "pdf")
|
||||||
io = open(fn, "w")
|
io = open(fn, "w")
|
||||||
writemime(io, MIME("application/pdf"), plt)
|
writemime(io, MIME("application/pdf"), plt)
|
||||||
@ -28,7 +28,7 @@ end
|
|||||||
pdf(fn::@compat(AbstractString)) = pdf(current(), fn)
|
pdf(fn::@compat(AbstractString)) = pdf(current(), fn)
|
||||||
|
|
||||||
|
|
||||||
function ps(plt::AbstractPlot, fn::@compat(AbstractString))
|
function ps(plt::Plot, fn::@compat(AbstractString))
|
||||||
fn = addExtension(fn, "ps")
|
fn = addExtension(fn, "ps")
|
||||||
io = open(fn, "w")
|
io = open(fn, "w")
|
||||||
writemime(io, MIME("application/postscript"), plt)
|
writemime(io, MIME("application/postscript"), plt)
|
||||||
@ -37,7 +37,7 @@ end
|
|||||||
ps(fn::@compat(AbstractString)) = ps(current(), fn)
|
ps(fn::@compat(AbstractString)) = ps(current(), fn)
|
||||||
|
|
||||||
|
|
||||||
function tex(plt::AbstractPlot, fn::@compat(AbstractString))
|
function tex(plt::Plot, fn::@compat(AbstractString))
|
||||||
fn = addExtension(fn, "tex")
|
fn = addExtension(fn, "tex")
|
||||||
io = open(fn, "w")
|
io = open(fn, "w")
|
||||||
writemime(io, MIME("application/x-tex"), plt)
|
writemime(io, MIME("application/x-tex"), plt)
|
||||||
@ -78,7 +78,7 @@ function addExtension(fn::@compat(AbstractString), ext::@compat(AbstractString))
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function savefig(plt::AbstractPlot, fn::@compat(AbstractString))
|
function savefig(plt::Plot, fn::@compat(AbstractString))
|
||||||
|
|
||||||
# get the extension
|
# get the extension
|
||||||
local ext
|
local ext
|
||||||
@ -101,7 +101,7 @@ savefig(fn::@compat(AbstractString)) = savefig(current(), fn)
|
|||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
gui(plt::AbstractPlot = current()) = display(PlotsDisplay(), plt)
|
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot)
|
function Base.display(::PlotsDisplay, plt::Plot)
|
||||||
prepare_output(plt)
|
prepare_output(plt)
|
||||||
@ -109,7 +109,7 @@ function Base.display(::PlotsDisplay, plt::Plot)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# override the REPL display to open a gui window
|
# override the REPL display to open a gui window
|
||||||
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::AbstractPlot) = gui(plt)
|
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
@ -123,12 +123,12 @@ const _mimeformats = Dict(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# a backup for html... passes to svg
|
# a backup for html... passes to svg
|
||||||
function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot)
|
function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
|
||||||
writemime(io, MIME("image/svg+xml"), plt)
|
writemime(io, MIME("image/svg+xml"), plt)
|
||||||
end
|
end
|
||||||
|
|
||||||
for mime in keys(_mimeformats)
|
for mime in keys(_mimeformats)
|
||||||
@eval function writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
|
@eval function Base.writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
|
||||||
prepare_output(plt)
|
prepare_output(plt)
|
||||||
_writemime(io, m, plt)
|
_writemime(io, m, plt)
|
||||||
end
|
end
|
||||||
@ -151,13 +151,13 @@ function setup_ijulia()
|
|||||||
global _ijulia_output
|
global _ijulia_output
|
||||||
_ijulia_output[1] = mimestr
|
_ijulia_output[1] = mimestr
|
||||||
end
|
end
|
||||||
function IJulia.display_dict(plt::AbstractPlot)
|
function IJulia.display_dict(plt::Plot)
|
||||||
global _ijulia_output
|
global _ijulia_output
|
||||||
Dict{ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt))
|
Dict{ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# IJulia.display_dict(plt::AbstractPlot) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
|
# IJulia.display_dict(plt::Plot) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
|
||||||
set_ijulia_output("text/html")
|
set_ijulia_output("text/html")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -174,15 +174,15 @@ function setup_atom()
|
|||||||
|
|
||||||
# connects the render function
|
# connects the render function
|
||||||
for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
|
for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
|
||||||
Atom.Media.media(AbstractPlot{T}, Atom.Media.Plot)
|
Atom.Media.media(Plot{T}, Atom.Media.Plot)
|
||||||
end
|
end
|
||||||
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
|
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
|
||||||
|
|
||||||
# Atom.displaysize(::AbstractPlot) = (535, 379)
|
# Atom.displaysize(::Plot) = (535, 379)
|
||||||
# Atom.displaytitle(plt::AbstractPlot) = "Plots.jl (backend: $(backend(plt)))"
|
# Atom.displaytitle(plt::Plot) = "Plots.jl (backend: $(backend(plt)))"
|
||||||
|
|
||||||
# this is like "display"... sends an html div with the plot to the PlotPane
|
# this is like "display"... sends an html div with the plot to the PlotPane
|
||||||
function Atom.Media.render(pane::Atom.PlotPane, plt::AbstractPlot)
|
function Atom.Media.render(pane::Atom.PlotPane, plt::Plot)
|
||||||
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
|
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
19
src/plot.jl
19
src/plot.jl
@ -95,6 +95,7 @@ end
|
|||||||
# natively by the backend
|
# natively by the backend
|
||||||
function _apply_series_recipe(plt::Plot, d::KW)
|
function _apply_series_recipe(plt::Plot, d::KW)
|
||||||
st = d[:seriestype]
|
st = d[:seriestype]
|
||||||
|
@show st
|
||||||
if st in supportedTypes()
|
if st in supportedTypes()
|
||||||
|
|
||||||
# getting ready to add the series... last update to subplot from anything
|
# getting ready to add the series... last update to subplot from anything
|
||||||
@ -138,7 +139,7 @@ function _apply_series_recipe(plt::Plot, d::KW)
|
|||||||
|
|
||||||
else
|
else
|
||||||
# get a sub list of series for this seriestype
|
# get a sub list of series for this seriestype
|
||||||
series_list = try
|
datalist = try
|
||||||
RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
|
RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
|
||||||
catch
|
catch
|
||||||
warn("Exception during apply_recipe(Val{$st}, ...) with types ($(typeof(d[:x])), $(typeof(d[:y])), $(typeof(d[:z])))")
|
warn("Exception during apply_recipe(Val{$st}, ...) with types ($(typeof(d[:x])), $(typeof(d[:y])), $(typeof(d[:z])))")
|
||||||
@ -146,9 +147,9 @@ function _apply_series_recipe(plt::Plot, d::KW)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# assuming there was no error, recursively apply the series recipes
|
# assuming there was no error, recursively apply the series recipes
|
||||||
for series in series_list
|
for data in datalist
|
||||||
if isa(series, Series)
|
if isa(data, RecipeData)
|
||||||
_apply_series_recipe(plt, series.d)
|
_apply_series_recipe(plt, data.d)
|
||||||
else
|
else
|
||||||
warn("Unhandled series: $(series_list)")
|
warn("Unhandled series: $(series_list)")
|
||||||
break
|
break
|
||||||
@ -221,6 +222,10 @@ function _plot!(plt::Plot, d::KW, args...)
|
|||||||
kw[:fillrange] = (kw[:y] - rib, kw[:y] + rib)
|
kw[:fillrange] = (kw[:y] - rib, kw[:y] + rib)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# add the plot index
|
||||||
|
plt.n += 1
|
||||||
|
kw[:series_plotindex] = plt.n
|
||||||
|
|
||||||
# check that the backend will support the command and add it to the list
|
# check that the backend will support the command and add it to the list
|
||||||
warnOnUnsupportedScales(plt.backend, kw)
|
warnOnUnsupportedScales(plt.backend, kw)
|
||||||
push!(kw_list, kw)
|
push!(kw_list, kw)
|
||||||
@ -248,9 +253,9 @@ function _plot!(plt::Plot, d::KW, args...)
|
|||||||
# this is it folks!
|
# this is it folks!
|
||||||
# TODO: we probably shouldn't use i for tracking series index, but rather explicitly track it in recipes
|
# TODO: we probably shouldn't use i for tracking series index, but rather explicitly track it in recipes
|
||||||
for (i,kw) in enumerate(kw_list)
|
for (i,kw) in enumerate(kw_list)
|
||||||
if !(get(kw, :seriestype, :none) in (:xerror, :yerror))
|
# if !(get(kw, :seriestype, :none) in (:xerror, :yerror))
|
||||||
plt.n += 1
|
# plt.n += 1
|
||||||
end
|
# end
|
||||||
|
|
||||||
# get the Subplot object to which the series belongs
|
# get the Subplot object to which the series belongs
|
||||||
sp = get(kw, :subplot, :auto)
|
sp = get(kw, :subplot, :auto)
|
||||||
|
|||||||
@ -226,6 +226,55 @@ end
|
|||||||
()
|
()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# create a path from steps
|
||||||
|
@recipe function f(::Type{Val{:steppre}}, x, y, z)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a bar plot as a filled step function
|
||||||
|
@recipe function f(::Type{Val{:bar}}, x, y, z)
|
||||||
|
nx, ny = length(x), length(y)
|
||||||
|
d[:x] = if nx == ny
|
||||||
|
# x is centers
|
||||||
|
halfwidths = 0.5 * diff(x)
|
||||||
|
vcat(halfwidths[1], halfwidths, halfwidths[end])
|
||||||
|
elseif nx == ny + 1
|
||||||
|
# x is edges
|
||||||
|
x
|
||||||
|
else
|
||||||
|
error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))")
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: use y/fillrange to compute new y/fillrange vectors
|
||||||
|
|
||||||
|
d[:seriestype] = :steppre
|
||||||
|
()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# # x is edges
|
||||||
|
# for i=1:n
|
||||||
|
# gr_fillrect(series, x[i], x[i+1], 0, y[i])
|
||||||
|
# end
|
||||||
|
# elseif length(x) == n
|
||||||
|
# # x is centers
|
||||||
|
# leftwidth = length(x) > 1 ? abs(0.5 * (x[2] - x[1])) : 0.5
|
||||||
|
# for i=1:n
|
||||||
|
# rightwidth = (i == n ? leftwidth : abs(0.5 * (x[i+1] - x[i])))
|
||||||
|
# gr_fillrect(series, x[i] - leftwidth, x[i] + rightwidth, 0, y[i])
|
||||||
|
# end
|
||||||
|
# else
|
||||||
|
# error("gr_barplot: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))")
|
||||||
|
# end
|
||||||
|
|
||||||
|
@recipe function f(::Type{Val{:hist}}, x, y, z)
|
||||||
|
edges, counts = Base.hist(y, d[:bins])
|
||||||
|
d[:x] = edges
|
||||||
|
d[:y] = counts
|
||||||
|
d[:seriestype] = :bar
|
||||||
|
()
|
||||||
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Box Plot
|
# Box Plot
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,8 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
|||||||
# n = plt.n
|
# n = plt.n
|
||||||
# attr = getattr(plt, n)
|
# attr = getattr(plt, n)
|
||||||
# plotIndex = convertSeriesIndex(plt, n)
|
# plotIndex = convertSeriesIndex(plt, n)
|
||||||
globalIndex = plt.n
|
# globalIndex = plt.n
|
||||||
|
globalIndex = d[:series_plotindex]
|
||||||
|
|
||||||
# # add defaults?
|
# # add defaults?
|
||||||
# for k in keys(_series_defaults)
|
# for k in keys(_series_defaults)
|
||||||
|
|||||||
@ -33,4 +33,14 @@ get_subplot(series::Series) = series.d[:subplot]
|
|||||||
get_subplot_index(plt::Plot, idx::Integer) = idx
|
get_subplot_index(plt::Plot, idx::Integer) = idx
|
||||||
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots)
|
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots)
|
||||||
|
|
||||||
|
series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||||
|
|
||||||
|
function should_add_to_legend(series::Series)
|
||||||
|
!(series.d[:label] == "" || series.d[:seriestype] in (
|
||||||
|
:hexbin,:hist2d,:hline,:vline,
|
||||||
|
:contour,:contour3d,:surface,:wireframe,
|
||||||
|
:heatmap,:path3d,:scatter3d, :pie, :image
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user