Compare commits
9 Commits
master
...
first_time
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a1fe30567 | ||
|
|
db685b6ee0 | ||
|
|
fcb9078838 | ||
|
|
3310025602 | ||
|
|
122a470078 | ||
|
|
bb0b6e5d33 | ||
|
|
7185e36795 | ||
|
|
d111c2ba91 | ||
|
|
5dff00e2a3 |
@ -220,6 +220,7 @@ end
|
|||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
const CURRENT_BACKEND = Plots.CurrentBackend(:gr)
|
||||||
|
gr()
|
||||||
|
|
||||||
end # module
|
end # module
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
const _arg_desc = KW(
|
const _arg_desc = Dict{Symbol,String}(
|
||||||
|
|
||||||
# series args
|
# series args
|
||||||
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
|
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
|
||||||
|
|||||||
100
src/args.jl
100
src/args.jl
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const _keyAliases = Dict{Symbol,Symbol}()
|
const _keyAliases = Dict{Symbol,Symbol}()
|
||||||
|
|
||||||
function add_aliases(sym::Symbol, aliases::Symbol...)
|
@noinline function add_aliases(sym::Symbol, aliases::Symbol...)
|
||||||
for alias in aliases
|
for alias in aliases
|
||||||
if haskey(_keyAliases, alias)
|
if haskey(_keyAliases, alias)
|
||||||
error("Already an alias $alias => $(_keyAliases[alias])... can't also alias $sym")
|
error("Already an alias $alias => $(_keyAliases[alias])... can't also alias $sym")
|
||||||
@ -11,7 +11,7 @@ function add_aliases(sym::Symbol, aliases::Symbol...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
|
@noinline function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
|
||||||
for (k,v) in aliases
|
for (k,v) in aliases
|
||||||
s = string(k)
|
s = string(k)
|
||||||
if '_' in s
|
if '_' in s
|
||||||
@ -84,17 +84,17 @@ const _histogram_like = [:histogram, :barhist, :barbins]
|
|||||||
const _line_like = [:line, :path, :steppre, :steppost]
|
const _line_like = [:line, :path, :steppre, :steppost]
|
||||||
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
|
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
|
||||||
|
|
||||||
like_histogram(seriestype::Symbol) = seriestype in _histogram_like
|
@noinline like_histogram(seriestype::Symbol) = seriestype in _histogram_like
|
||||||
like_line(seriestype::Symbol) = seriestype in _line_like
|
@noinline like_line(seriestype::Symbol) = seriestype in _line_like
|
||||||
like_surface(seriestype::Symbol) = seriestype in _surface_like
|
@noinline like_surface(seriestype::Symbol) = seriestype in _surface_like
|
||||||
|
|
||||||
is3d(seriestype::Symbol) = seriestype in _3dTypes
|
@noinline is3d(seriestype::Symbol) = seriestype in _3dTypes
|
||||||
is3d(series::Series) = is3d(series.plotattributes)
|
@noinline is3d(series::Series) = is3d(series.plotattributes)
|
||||||
is3d(plotattributes::KW) = trueOrAllTrue(is3d, Symbol(plotattributes[:seriestype]))
|
@noinline is3d(plotattributes::KW) = trueOrAllTrue(is3d, Symbol(plotattributes[:seriestype]))
|
||||||
|
|
||||||
is3d(sp::Subplot) = string(sp.attr[:projection]) == "3d"
|
@noinline is3d(sp::Subplot) = string(sp.attr[:projection]) == "3d"
|
||||||
ispolar(sp::Subplot) = string(sp.attr[:projection]) == "polar"
|
@noinline ispolar(sp::Subplot) = string(sp.attr[:projection]) == "polar"
|
||||||
ispolar(series::Series) = ispolar(series.plotattributes[:subplot])
|
@noinline ispolar(series::Series) = ispolar(series.plotattributes[:subplot])
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
@ -188,9 +188,9 @@ const _allGridSyms = [:x, :y, :z,
|
|||||||
:all, :both, :on, :yes, :show,
|
:all, :both, :on, :yes, :show,
|
||||||
:none, :off, :no, :hide]
|
:none, :off, :no, :hide]
|
||||||
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
|
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
|
||||||
hasgrid(arg::Nothing, letter) = false
|
@noinline hasgrid(arg::Nothing, letter) = false
|
||||||
hasgrid(arg::Bool, letter) = arg
|
@noinline hasgrid(arg::Bool, letter) = arg
|
||||||
function hasgrid(arg::Symbol, letter)
|
@noinline function hasgrid(arg::Symbol, letter)
|
||||||
if arg in _allGridSyms
|
if arg in _allGridSyms
|
||||||
arg in (:all, :both, :on) || occursin(string(letter), string(arg))
|
arg in (:all, :both, :on) || occursin(string(letter), string(arg))
|
||||||
else
|
else
|
||||||
@ -198,7 +198,7 @@ function hasgrid(arg::Symbol, letter)
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
|
@noinline hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
|
||||||
|
|
||||||
const _allShowaxisSyms = [:x, :y, :z,
|
const _allShowaxisSyms = [:x, :y, :z,
|
||||||
:xy, :xz, :yx, :yz, :zx, :zy,
|
:xy, :xz, :yx, :yz, :zx, :zy,
|
||||||
@ -206,9 +206,9 @@ const _allShowaxisSyms = [:x, :y, :z,
|
|||||||
:all, :both, :on, :yes, :show,
|
:all, :both, :on, :yes, :show,
|
||||||
:off, :no, :hide]
|
:off, :no, :hide]
|
||||||
const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)]
|
const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)]
|
||||||
showaxis(arg::Nothing, letter) = false
|
@noinline showaxis(arg::Nothing, letter) = false
|
||||||
showaxis(arg::Bool, letter) = arg
|
@noinline showaxis(arg::Bool, letter) = arg
|
||||||
function showaxis(arg::Symbol, letter)
|
@noinline function showaxis(arg::Symbol, letter)
|
||||||
if arg in _allGridSyms
|
if arg in _allGridSyms
|
||||||
arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg))
|
arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg))
|
||||||
else
|
else
|
||||||
@ -216,7 +216,7 @@ function showaxis(arg::Symbol, letter)
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
showaxis(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
|
@noinline showaxis(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
|
||||||
|
|
||||||
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
|
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
|
||||||
const _framestyleAliases = Dict{Symbol, Symbol}(
|
const _framestyleAliases = Dict{Symbol, Symbol}(
|
||||||
@ -448,7 +448,7 @@ const _initial_defaults = deepcopy(_all_defaults)
|
|||||||
const _initial_axis_defaults = deepcopy(_axis_defaults)
|
const _initial_axis_defaults = deepcopy(_axis_defaults)
|
||||||
|
|
||||||
# to be able to reset font sizes to initial values
|
# to be able to reset font sizes to initial values
|
||||||
const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefontsize],
|
const _initial_fontsizes = Dict{Any,Any}(:titlefontsize => _subplot_defaults[:titlefontsize],
|
||||||
:legendfontsize => _subplot_defaults[:legendfontsize],
|
:legendfontsize => _subplot_defaults[:legendfontsize],
|
||||||
:tickfontsize => _axis_defaults[:tickfontsize],
|
:tickfontsize => _axis_defaults[:tickfontsize],
|
||||||
:guidefontsize => _axis_defaults[:guidefontsize])
|
:guidefontsize => _axis_defaults[:guidefontsize])
|
||||||
@ -459,15 +459,15 @@ RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
makeplural(s::Symbol) = Symbol(string(s,"s"))
|
@noinline makeplural(s::Symbol) = Symbol(string(s,"s"))
|
||||||
|
|
||||||
autopick(arr::AVec, idx::Integer) = arr[mod1(idx,length(arr))]
|
@noinline autopick(arr::AVec, idx::Integer) = arr[mod1(idx,length(arr))]
|
||||||
autopick(notarr, idx::Integer) = notarr
|
@noinline autopick(notarr, idx::Integer) = notarr
|
||||||
|
|
||||||
autopick_ignore_none_auto(arr::AVec, idx::Integer) = autopick(setdiff(arr, [:none, :auto]), idx)
|
@noinline autopick_ignore_none_auto(arr::AVec, idx::Integer) = autopick(setdiff(arr, [:none, :auto]), idx)
|
||||||
autopick_ignore_none_auto(notarr, idx::Integer) = notarr
|
@noinline autopick_ignore_none_auto(notarr, idx::Integer) = notarr
|
||||||
|
|
||||||
function aliasesAndAutopick(plotattributes::KW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int)
|
@noinline function aliasesAndAutopick(plotattributes::KW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int)
|
||||||
if plotattributes[sym] == :auto
|
if plotattributes[sym] == :auto
|
||||||
plotattributes[sym] = autopick_ignore_none_auto(options, plotIndex)
|
plotattributes[sym] = autopick_ignore_none_auto(options, plotIndex)
|
||||||
elseif haskey(aliases, plotattributes[sym])
|
elseif haskey(aliases, plotattributes[sym])
|
||||||
@ -475,7 +475,7 @@ function aliasesAndAutopick(plotattributes::KW, sym::Symbol, aliases::Dict{Symbo
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function aliases(aliasMap::Dict{Symbol,Symbol}, val)
|
@noinline function aliases(aliasMap::Dict{Symbol,Symbol}, val)
|
||||||
sortedkeys(filter((k,v)-> v==val, aliasMap))
|
sortedkeys(filter((k,v)-> v==val, aliasMap))
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -879,9 +879,9 @@ function processFontArg!(plotattributes::KW, fontname::Symbol, arg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
|
@noinline _replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
|
||||||
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
|
@noinline _replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
|
||||||
_replace_markershape(shape) = shape
|
@noinline _replace_markershape(shape) = shape
|
||||||
|
|
||||||
function _add_markershape(plotattributes::KW)
|
function _add_markershape(plotattributes::KW)
|
||||||
# add the markershape if it needs to be added... hack to allow "m=10" to add a shape,
|
# add the markershape if it needs to be added... hack to allow "m=10" to add a shape,
|
||||||
@ -1074,7 +1074,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
# this is when given a vector-type of values to group by
|
# this is when given a vector-type of values to group by
|
||||||
function extractGroupArgs(v::AVec, args...; legendEntry = string)
|
@noinline function extractGroupArgs(v::AVec, args...; legendEntry = string)
|
||||||
groupLabels = sort(collect(unique(v)))
|
groupLabels = sort(collect(unique(v)))
|
||||||
n = length(groupLabels)
|
n = length(groupLabels)
|
||||||
if n > 100
|
if n > 100
|
||||||
@ -1084,17 +1084,17 @@ function extractGroupArgs(v::AVec, args...; legendEntry = string)
|
|||||||
GroupBy(map(legendEntry, groupLabels), groupIds)
|
GroupBy(map(legendEntry, groupLabels), groupIds)
|
||||||
end
|
end
|
||||||
|
|
||||||
legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
|
@noinline legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
|
||||||
|
|
||||||
# this is when given a tuple of vectors of values to group by
|
# this is when given a tuple of vectors of values to group by
|
||||||
function extractGroupArgs(vs::Tuple, args...)
|
@noinline function extractGroupArgs(vs::Tuple, args...)
|
||||||
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
|
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
|
||||||
v = map(tuple, vs...)
|
v = map(tuple, vs...)
|
||||||
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
|
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
|
||||||
end
|
end
|
||||||
|
|
||||||
# allow passing NamedTuples for a named legend entry
|
# allow passing NamedTuples for a named legend entry
|
||||||
legendEntryFromTuple(ns::NamedTuple) =
|
@noinline legendEntryFromTuple(ns::NamedTuple) =
|
||||||
join(["$k = $v" for (k, v) in pairs(ns)], ", ")
|
join(["$k = $v" for (k, v) in pairs(ns)], ", ")
|
||||||
|
|
||||||
function extractGroupArgs(vs::NamedTuple, args...)
|
function extractGroupArgs(vs::NamedTuple, args...)
|
||||||
@ -1104,22 +1104,22 @@ function extractGroupArgs(vs::NamedTuple, args...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# expecting a mapping of "group label" to "group indices"
|
# expecting a mapping of "group label" to "group indices"
|
||||||
function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
|
@noinline function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
|
||||||
groupLabels = sortedkeys(idxmap)
|
groupLabels = sortedkeys(idxmap)
|
||||||
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
|
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
|
||||||
GroupBy(groupLabels, groupIds)
|
GroupBy(groupLabels, groupIds)
|
||||||
end
|
end
|
||||||
|
|
||||||
filter_data(v::AVec, idxfilter::AVec{Int}) = v[idxfilter]
|
@noinline filter_data(v::AVec, idxfilter::AVec{Int}) = v[idxfilter]
|
||||||
filter_data(v, idxfilter) = v
|
@noinline filter_data(v, idxfilter) = v
|
||||||
|
|
||||||
function filter_data!(plotattributes::KW, idxfilter)
|
@noinline function filter_data!(plotattributes::KW, idxfilter)
|
||||||
for s in (:x, :y, :z)
|
for s in (:x, :y, :z)
|
||||||
plotattributes[s] = filter_data(get(plotattributes, s, nothing), idxfilter)
|
plotattributes[s] = filter_data(get(plotattributes, s, nothing), idxfilter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _filter_input_data!(plotattributes::KW)
|
@noinline function _filter_input_data!(plotattributes::KW)
|
||||||
idxfilter = pop!(plotattributes, :idxfilter, nothing)
|
idxfilter = pop!(plotattributes, :idxfilter, nothing)
|
||||||
if idxfilter !== nothing
|
if idxfilter !== nothing
|
||||||
filter_data!(plotattributes, idxfilter)
|
filter_data!(plotattributes, idxfilter)
|
||||||
@ -1182,7 +1182,7 @@ end
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
function convertLegendValue(val::Symbol)
|
@noinline function convertLegendValue(val::Symbol)
|
||||||
if val in (:both, :all, :yes)
|
if val in (:both, :all, :yes)
|
||||||
:best
|
:best
|
||||||
elseif val in (:no, :none)
|
elseif val in (:no, :none)
|
||||||
@ -1193,10 +1193,10 @@ function convertLegendValue(val::Symbol)
|
|||||||
error("Invalid symbol for legend: $val")
|
error("Invalid symbol for legend: $val")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
convertLegendValue(val::Bool) = val ? :best : :none
|
@noinline convertLegendValue(val::Bool) = val ? :best : :none
|
||||||
convertLegendValue(val::Nothing) = :none
|
@noinline convertLegendValue(val::Nothing) = :none
|
||||||
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
|
@noinline convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
|
||||||
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
|
@noinline convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -1205,12 +1205,12 @@ convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
|
|||||||
# multi-row matrices will give a column
|
# multi-row matrices will give a column
|
||||||
# InputWrapper just gives the contents
|
# InputWrapper just gives the contents
|
||||||
# anything else is returned as-is
|
# anything else is returned as-is
|
||||||
function slice_arg(v::AMat, idx::Int)
|
@noinline function slice_arg(v::AMat, idx::Int)
|
||||||
c = mod1(idx, size(v,2))
|
c = mod1(idx, size(v,2))
|
||||||
size(v,1) == 1 ? v[1,c] : v[:,c]
|
size(v,1) == 1 ? v[1,c] : v[:,c]
|
||||||
end
|
end
|
||||||
slice_arg(wrapper::InputWrapper, idx) = wrapper.obj
|
@noinline slice_arg(wrapper::InputWrapper, idx) = wrapper.obj
|
||||||
slice_arg(v, idx) = v
|
@noinline slice_arg(v, idx) = v
|
||||||
|
|
||||||
|
|
||||||
# given an argument key (k), we want to extract the argument value for this index.
|
# given an argument key (k), we want to extract the argument value for this index.
|
||||||
@ -1509,9 +1509,9 @@ end
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
has_black_border_for_default(st) = error("The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.")
|
@noinline has_black_border_for_default(st) = error("The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.")
|
||||||
has_black_border_for_default(st::Function) = error("The seriestype attribute only accepts Symbols, you passed the function $st.")
|
@noinline has_black_border_for_default(st::Function) = error("The seriestype attribute only accepts Symbols, you passed the function $st.")
|
||||||
function has_black_border_for_default(st::Symbol)
|
@noinline function has_black_border_for_default(st::Symbol)
|
||||||
like_histogram(st) || st in (:hexbin, :bar, :shape)
|
like_histogram(st) || st in (:hexbin, :bar, :shape)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -754,5 +754,5 @@ function axis_drawing_info(sp::Subplot)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs
|
Any[xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs]
|
||||||
end
|
end
|
||||||
|
|||||||
@ -47,17 +47,17 @@ end
|
|||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
# don't do anything as a default
|
# don't do anything as a default
|
||||||
_create_backend_figure(plt::Plot) = nothing
|
@noinline _create_backend_figure(plt::Plot) = nothing
|
||||||
_prepare_plot_object(plt::Plot) = nothing
|
@noinline _prepare_plot_object(plt::Plot) = nothing
|
||||||
_initialize_subplot(plt::Plot, sp::Subplot) = nothing
|
@noinline _initialize_subplot(plt::Plot, sp::Subplot) = nothing
|
||||||
|
|
||||||
_series_added(plt::Plot, series::Series) = nothing
|
@noinline _series_added(plt::Plot, series::Series) = nothing
|
||||||
_series_updated(plt::Plot, series::Series) = nothing
|
@noinline _series_updated(plt::Plot, series::Series) = nothing
|
||||||
|
|
||||||
_before_layout_calcs(plt::Plot) = nothing
|
@noinline _before_layout_calcs(plt::Plot) = nothing
|
||||||
|
|
||||||
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefontsize] * pt
|
@noinline title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefontsize] * pt
|
||||||
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefontsize] * pt
|
@noinline guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefontsize] * pt
|
||||||
|
|
||||||
"Returns the (width,height) of a text label."
|
"Returns the (width,height) of a text label."
|
||||||
function text_size(lablen::Int, sz::Number, rot::Number = 0)
|
function text_size(lablen::Int, sz::Number, rot::Number = 0)
|
||||||
@ -123,20 +123,32 @@ function _update_min_padding!(sp::Subplot)
|
|||||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||||
end
|
end
|
||||||
|
|
||||||
_update_plot_object(plt::Plot) = nothing
|
@noinline _update_plot_object(plt::Plot) = nothing
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
mutable struct CurrentBackend
|
mutable struct CurrentBackend{sym,T}
|
||||||
sym::Symbol
|
pkg::T
|
||||||
pkg::AbstractBackend
|
end
|
||||||
|
function CurrentBackend(sym::Symbol)
|
||||||
|
bkend = _backend_instance(sym)
|
||||||
|
CurrentBackend{sym,typeof(bkend)}(bkend)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Base.getproperty(bkend::CurrentBackend{sym,T},x::Symbol) where {sym,T}
|
||||||
|
if x === :sym
|
||||||
|
return sym
|
||||||
|
elseif x === :pkg
|
||||||
|
return getfield(bkend,:pkg)
|
||||||
|
else
|
||||||
|
error("Must be sym or pkg")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
_fallback_default_backend() = backend(GRBackend())
|
@noinline _fallback_default_backend() = backend(GRBackend())
|
||||||
|
|
||||||
function _pick_default_backend()
|
function _pick_default_backend()
|
||||||
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
|
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
|
||||||
@ -177,8 +189,7 @@ function backend(pkg::AbstractBackend)
|
|||||||
_initialize_backend(pkg)
|
_initialize_backend(pkg)
|
||||||
push!(_initialized_backends, sym)
|
push!(_initialized_backends, sym)
|
||||||
end
|
end
|
||||||
CURRENT_BACKEND.sym = sym
|
CURRENT_BACKEND = Plots.CurrentBackend(sym)
|
||||||
CURRENT_BACKEND.pkg = pkg
|
|
||||||
pkg
|
pkg
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -294,9 +305,8 @@ function _initialize_backend(pkg::AbstractBackend)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_initialize_backend(pkg::GRBackend) = nothing
|
@noinline _initialize_backend(pkg::GRBackend) = nothing
|
||||||
|
@noinline _initialize_backend(pkg::PlotlyBackend) = nothing
|
||||||
_initialize_backend(pkg::PlotlyBackend) = nothing
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|||||||
1087
src/backends/gr.jl
1087
src/backends/gr.jl
File diff suppressed because it is too large
Load Diff
@ -137,7 +137,7 @@ const _shape_keys = Symbol[
|
|||||||
:x,
|
:x,
|
||||||
]
|
]
|
||||||
|
|
||||||
const _shapes = KW(
|
const _shapes = Dict{Symbol,Shape}(
|
||||||
:circle => makeshape(20),
|
:circle => makeshape(20),
|
||||||
:rect => makeshape(4, offset=-0.25),
|
:rect => makeshape(4, offset=-0.25),
|
||||||
:diamond => makeshape(4),
|
:diamond => makeshape(4),
|
||||||
|
|||||||
@ -188,29 +188,29 @@ parent_bbox(layout::AbstractLayout) = bbox(parent(layout))
|
|||||||
# padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
|
# padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
|
||||||
# padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
|
# padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
|
||||||
|
|
||||||
update_position!(layout::AbstractLayout) = nothing
|
@noinline update_position!(layout::AbstractLayout) = nothing
|
||||||
update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
|
@noinline update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
|
||||||
|
|
||||||
left(layout::AbstractLayout) = left(bbox(layout))
|
@noinline left(layout::AbstractLayout) = left(bbox(layout))
|
||||||
top(layout::AbstractLayout) = top(bbox(layout))
|
@noinline top(layout::AbstractLayout) = top(bbox(layout))
|
||||||
right(layout::AbstractLayout) = right(bbox(layout))
|
@noinline right(layout::AbstractLayout) = right(bbox(layout))
|
||||||
bottom(layout::AbstractLayout) = bottom(bbox(layout))
|
@noinline bottom(layout::AbstractLayout) = bottom(bbox(layout))
|
||||||
width(layout::AbstractLayout) = width(bbox(layout))
|
@noinline width(layout::AbstractLayout) = width(bbox(layout))
|
||||||
height(layout::AbstractLayout) = height(bbox(layout))
|
@noinline height(layout::AbstractLayout) = height(bbox(layout))
|
||||||
|
|
||||||
# pass these through to the bbox methods if there's no plotarea
|
# pass these through to the bbox methods if there's no plotarea
|
||||||
plotarea(layout::AbstractLayout) = bbox(layout)
|
@noinline plotarea(layout::AbstractLayout) = bbox(layout)
|
||||||
plotarea!(layout::AbstractLayout, bb::BoundingBox) = bbox!(layout, bb)
|
@noinline plotarea!(layout::AbstractLayout, bb::BoundingBox) = bbox!(layout, bb)
|
||||||
|
|
||||||
attr(layout::AbstractLayout, k::Symbol) = layout.attr[k]
|
@noinline attr(layout::AbstractLayout, k::Symbol) = layout.attr[k]
|
||||||
attr(layout::AbstractLayout, k::Symbol, v) = get(layout.attr, k, v)
|
@noinline attr(layout::AbstractLayout, k::Symbol, v) = get(layout.attr, k, v)
|
||||||
attr!(layout::AbstractLayout, v, k::Symbol) = (layout.attr[k] = v)
|
@noinline attr!(layout::AbstractLayout, v, k::Symbol) = (layout.attr[k] = v)
|
||||||
hasattr(layout::AbstractLayout, k::Symbol) = haskey(layout.attr, k)
|
@noinline hasattr(layout::AbstractLayout, k::Symbol) = haskey(layout.attr, k)
|
||||||
|
|
||||||
leftpad(layout::AbstractLayout) = 0mm
|
@noinline leftpad(layout::AbstractLayout) = 0mm
|
||||||
toppad(layout::AbstractLayout) = 0mm
|
@noinline toppad(layout::AbstractLayout) = 0mm
|
||||||
rightpad(layout::AbstractLayout) = 0mm
|
@noinline rightpad(layout::AbstractLayout) = 0mm
|
||||||
bottompad(layout::AbstractLayout) = 0mm
|
@noinline bottompad(layout::AbstractLayout) = 0mm
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
# -----------------------------------------------------------
|
||||||
# RootLayout
|
# RootLayout
|
||||||
@ -227,8 +227,8 @@ bbox(::RootLayout) = defaultbox
|
|||||||
|
|
||||||
# contains blank space
|
# contains blank space
|
||||||
mutable struct EmptyLayout <: AbstractLayout
|
mutable struct EmptyLayout <: AbstractLayout
|
||||||
parent::AbstractLayout
|
parent
|
||||||
bbox::BoundingBox
|
bbox#::BoundingBox
|
||||||
attr::KW # store label, width, and height for initialization
|
attr::KW # store label, width, and height for initialization
|
||||||
# label # this is the label that the subplot will take (since we create a layout before initialization)
|
# label # this is the label that the subplot will take (since we create a layout before initialization)
|
||||||
end
|
end
|
||||||
@ -245,12 +245,12 @@ _update_min_padding!(layout::EmptyLayout) = nothing
|
|||||||
|
|
||||||
# nested, gridded layout with optional size percentages
|
# nested, gridded layout with optional size percentages
|
||||||
mutable struct GridLayout <: AbstractLayout
|
mutable struct GridLayout <: AbstractLayout
|
||||||
parent::AbstractLayout
|
parent
|
||||||
minpad::Tuple # leftpad, toppad, rightpad, bottompad
|
minpad::Tuple{AbsoluteLength,AbsoluteLength,AbsoluteLength,AbsoluteLength} # leftpad, toppad, rightpad, bottompad
|
||||||
bbox::BoundingBox
|
bbox#::BoundingBox
|
||||||
grid::Matrix{AbstractLayout} # Nested layouts. Each position is a AbstractLayout, which allows for arbitrary recursion
|
grid::Matrix{Any} # Nested layouts. Each position is a AbstractLayout, which allows for arbitrary recursion
|
||||||
widths::Vector{Measure}
|
widths::Vector{Any}
|
||||||
heights::Vector{Measure}
|
heights::Vector{Any}
|
||||||
attr::KW
|
attr::KW
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -268,14 +268,14 @@ function GridLayout(dims...;
|
|||||||
widths = zeros(dims[2]),
|
widths = zeros(dims[2]),
|
||||||
heights = zeros(dims[1]),
|
heights = zeros(dims[1]),
|
||||||
kw...)
|
kw...)
|
||||||
grid = Matrix{AbstractLayout}(undef, dims...)
|
grid = Matrix{Any}(undef, dims...)
|
||||||
layout = GridLayout(
|
layout = GridLayout(
|
||||||
parent,
|
parent,
|
||||||
(20mm, 5mm, 2mm, 10mm),
|
(20mm, 5mm, 2mm, 10mm),
|
||||||
defaultbox,
|
defaultbox,
|
||||||
grid,
|
grid,
|
||||||
Measure[w*pct for w in widths],
|
Any[w*pct for w in widths],
|
||||||
Measure[h*pct for h in heights],
|
Any[h*pct for h in heights],
|
||||||
# convert(Vector{Float64}, widths),
|
# convert(Vector{Float64}, widths),
|
||||||
# convert(Vector{Float64}, heights),
|
# convert(Vector{Float64}, heights),
|
||||||
KW(kw))
|
KW(kw))
|
||||||
@ -349,18 +349,18 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
|||||||
# # create a matrix for each minimum padding direction
|
# # create a matrix for each minimum padding direction
|
||||||
# _update_min_padding!(layout)
|
# _update_min_padding!(layout)
|
||||||
|
|
||||||
minpad_left = map(leftpad, layout.grid)
|
minpad_left::Matrix{AbsoluteLength} = map(leftpad, layout.grid)
|
||||||
minpad_top = map(toppad, layout.grid)
|
minpad_top::Matrix{AbsoluteLength} = map(toppad, layout.grid)
|
||||||
minpad_right = map(rightpad, layout.grid)
|
minpad_right::Matrix{AbsoluteLength} = map(rightpad, layout.grid)
|
||||||
minpad_bottom = map(bottompad, layout.grid)
|
minpad_bottom::Matrix{AbsoluteLength} = map(bottompad, layout.grid)
|
||||||
|
|
||||||
# get the max horizontal (left and right) padding over columns,
|
# get the max horizontal (left and right) padding over columns,
|
||||||
# and max vertical (bottom and top) padding over rows
|
# and max vertical (bottom and top) padding over rows
|
||||||
# TODO: add extra padding here
|
# TODO: add extra padding here
|
||||||
pad_left = maximum(minpad_left, dims = 1)
|
pad_left::Matrix{AbsoluteLength} = maximum(minpad_left, dims = 1)
|
||||||
pad_top = maximum(minpad_top, dims = 2)
|
pad_top::Matrix{AbsoluteLength} = maximum(minpad_top, dims = 2)
|
||||||
pad_right = maximum(minpad_right, dims = 1)
|
pad_right::Matrix{AbsoluteLength} = maximum(minpad_right, dims = 1)
|
||||||
pad_bottom = maximum(minpad_bottom, dims = 2)
|
pad_bottom::Matrix{AbsoluteLength} = maximum(minpad_bottom, dims = 2)
|
||||||
|
|
||||||
# make sure the perimeter match the parent
|
# make sure the perimeter match the parent
|
||||||
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
|
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
|
||||||
@ -389,14 +389,14 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
|||||||
child = layout[r,c]
|
child = layout[r,c]
|
||||||
|
|
||||||
# get the top-left corner of this child... the first one is top-left of the parent (i.e. layout)
|
# get the top-left corner of this child... the first one is top-left of the parent (i.e. layout)
|
||||||
child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c-1].bbox))
|
child_left::AbsoluteLength = (c == 1 ? left(layout.bbox) : right(layout[r, c-1].bbox))
|
||||||
child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r-1, c].bbox))
|
child_top::AbsoluteLength = (r == 1 ? top(layout.bbox) : bottom(layout[r-1, c].bbox))
|
||||||
|
|
||||||
# compute plot area
|
# compute plot area
|
||||||
plotarea_left = child_left + pad_left[c]
|
plotarea_left::AbsoluteLength = child_left + pad_left[c]
|
||||||
plotarea_top = child_top + pad_top[r]
|
plotarea_top::AbsoluteLength = child_top + pad_top[r]
|
||||||
plotarea_width = total_plotarea_horizontal * layout.widths[c]
|
plotarea_width::AbsoluteLength = total_plotarea_horizontal * layout.widths[c]
|
||||||
plotarea_height = total_plotarea_vertical * layout.heights[r]
|
plotarea_height::AbsoluteLength = total_plotarea_vertical * layout.heights[r]
|
||||||
plotarea!(child, BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height))
|
plotarea!(child, BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height))
|
||||||
|
|
||||||
# compute child bbox
|
# compute child bbox
|
||||||
@ -512,14 +512,14 @@ end
|
|||||||
|
|
||||||
# # just a single subplot
|
# # just a single subplot
|
||||||
# function build_layout(sp::Subplot, n::Integer)
|
# function build_layout(sp::Subplot, n::Integer)
|
||||||
# sp, Subplot[sp], SubplotMap(gensym() => sp)
|
# sp, Subplot[sp], KW(gensym() => sp)
|
||||||
# end
|
# end
|
||||||
|
|
||||||
# n is the number of subplots... build a grid and initialize the inner subplots recursively
|
# n is the number of subplots... build a grid and initialize the inner subplots recursively
|
||||||
function build_layout(layout::GridLayout, n::Integer)
|
function build_layout(layout::GridLayout, n::Integer)
|
||||||
nr, nc = size(layout)
|
nr, nc = size(layout)
|
||||||
subplots = Subplot[]
|
subplots = Any[]
|
||||||
spmap = SubplotMap()
|
spmap = KW()
|
||||||
i = 0
|
i = 0
|
||||||
for r=1:nr, c=1:nc
|
for r=1:nr, c=1:nc
|
||||||
l = layout[r,c]
|
l = layout[r,c]
|
||||||
@ -560,8 +560,8 @@ end
|
|||||||
# TODO... much of the logic overlaps with the method above... can we merge?
|
# TODO... much of the logic overlaps with the method above... can we merge?
|
||||||
function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
|
function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
|
||||||
nr, nc = size(layout)
|
nr, nc = size(layout)
|
||||||
subplots = Subplot[]
|
subplots = Any[]
|
||||||
spmap = SubplotMap()
|
spmap = KW()
|
||||||
i = 0
|
i = 0
|
||||||
for r=1:nr, c=1:nc
|
for r=1:nr, c=1:nc
|
||||||
l = layout[r,c]
|
l = layout[r,c]
|
||||||
|
|||||||
@ -129,29 +129,29 @@ savefig(fn::AbstractString) = savefig(current(), fn)
|
|||||||
|
|
||||||
Display a plot using the backends' gui window
|
Display a plot using the backends' gui window
|
||||||
"""
|
"""
|
||||||
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
|
@noinline gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
|
||||||
|
|
||||||
# IJulia only... inline display
|
# IJulia only... inline display
|
||||||
function inline(plt::Plot = current())
|
@noinline function inline(plt::Plot = current())
|
||||||
isijulia() || error("inline() is IJulia-only")
|
isijulia() || error("inline() is IJulia-only")
|
||||||
Main.IJulia.clear_output(true)
|
Main.IJulia.clear_output(true)
|
||||||
display(Main.IJulia.InlineDisplay(), plt)
|
display(Main.IJulia.InlineDisplay(), plt)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot)
|
@noinline function Base.display(::PlotsDisplay, plt::Plot)
|
||||||
prepare_output(plt)
|
prepare_output(plt)
|
||||||
_display(plt)
|
_display(plt)
|
||||||
end
|
end
|
||||||
|
|
||||||
_do_plot_show(plt, showval::Bool) = showval && gui(plt)
|
@noinline _do_plot_show(plt, showval::Bool) = showval && gui(plt)
|
||||||
function _do_plot_show(plt, showval::Symbol)
|
@noinline function _do_plot_show(plt, showval::Symbol)
|
||||||
showval == :gui && gui(plt)
|
showval == :gui && gui(plt)
|
||||||
showval in (:inline,:ijulia) && inline(plt)
|
showval in (:inline,:ijulia) && inline(plt)
|
||||||
end
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
const _best_html_output_type = KW(
|
const _best_html_output_type = Dict{Symbol,Symbol}(
|
||||||
:pyplot => :png,
|
:pyplot => :png,
|
||||||
:unicodeplots => :txt,
|
:unicodeplots => :txt,
|
||||||
:plotlyjs => :html,
|
:plotlyjs => :html,
|
||||||
@ -159,7 +159,7 @@ const _best_html_output_type = KW(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# a backup for html... passes to svg or png depending on the html_output_format arg
|
# a backup for html... passes to svg or png depending on the html_output_format arg
|
||||||
function _show(io::IO, ::MIME"text/html", plt::Plot)
|
@noinline function _show(io::IO, ::MIME"text/html", plt::Plot)
|
||||||
output_type = Symbol(plt.attr[:html_output_format])
|
output_type = Symbol(plt.attr[:html_output_format])
|
||||||
if output_type == :auto
|
if output_type == :auto
|
||||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||||
@ -178,11 +178,11 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# delegate showable to _show instead
|
# delegate showable to _show instead
|
||||||
function Base.showable(m::M, plt::P) where {M<:MIME, P<:Plot}
|
@noinline function Base.showable(m::M, plt::P) where {M<:MIME, P<:Plot}
|
||||||
return hasmethod(_show, Tuple{IO, M, P})
|
return hasmethod(_show, Tuple{IO, M, P})
|
||||||
end
|
end
|
||||||
|
|
||||||
function _display(plt::Plot)
|
@noinline function _display(plt::Plot)
|
||||||
@warn("_display is not defined for this backend.")
|
@warn("_display is not defined for this backend.")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml
|
|||||||
end
|
end
|
||||||
|
|
||||||
# default text/plain for all backends
|
# default text/plain for all backends
|
||||||
_show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
|
@noinline _show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
|
||||||
|
|
||||||
"Close all open gui windows of the current backend"
|
"Close all open gui windows of the current backend"
|
||||||
closeall() = closeall(backend())
|
closeall() = closeall(backend())
|
||||||
@ -228,7 +228,7 @@ closeall() = closeall(backend())
|
|||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# Atom PlotPane
|
# Atom PlotPane
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
function showjuno(io::IO, m, plt)
|
@noinline function showjuno(io::IO, m, plt)
|
||||||
sz = plt[:size]
|
sz = plt[:size]
|
||||||
dpi = plt[:dpi]
|
dpi = plt[:dpi]
|
||||||
thickness_scaling = plt[:thickness_scaling]
|
thickness_scaling = plt[:thickness_scaling]
|
||||||
@ -250,7 +250,7 @@ function showjuno(io::IO, m, plt)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
|
@noinline function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
|
||||||
if Symbol(plt.attr[:html_output_format]) ≠ :svg
|
if Symbol(plt.attr[:html_output_format]) ≠ :svg
|
||||||
throw(MethodError(show, (typeof(m), typeof(plt))))
|
throw(MethodError(show, (typeof(m), typeof(plt))))
|
||||||
else
|
else
|
||||||
@ -258,4 +258,4 @@ function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_showjuno(io::IO, m, plt) = _show(io, m, plt)
|
@noinline _showjuno(io::IO, m, plt) = _show(io, m, plt)
|
||||||
|
|||||||
@ -3,11 +3,11 @@
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# preprocessing
|
# preprocessing
|
||||||
|
|
||||||
function command_idx(kw_list::AVec{KW}, kw::KW)
|
@noinline function command_idx(kw_list::AVec{KW}, kw::KW)
|
||||||
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function _expand_seriestype_array(plotattributes::KW, args)
|
@noinline function _expand_seriestype_array(plotattributes::KW, args)
|
||||||
sts = get(plotattributes, :seriestype, :path)
|
sts = get(plotattributes, :seriestype, :path)
|
||||||
if typeof(sts) <: AbstractArray
|
if typeof(sts) <: AbstractArray
|
||||||
delete!(plotattributes, :seriestype)
|
delete!(plotattributes, :seriestype)
|
||||||
@ -23,7 +23,7 @@ function _expand_seriestype_array(plotattributes::KW, args)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _preprocess_args(plotattributes::KW, args, still_to_process::Vector{RecipeData})
|
@noinline function _preprocess_args(plotattributes::KW, args, still_to_process::Vector{RecipeData})
|
||||||
# the grouping mechanism is a recipe on a GroupBy object
|
# the grouping mechanism is a recipe on a GroupBy object
|
||||||
# we simply add the GroupBy object to the front of the args list to allow
|
# we simply add the GroupBy object to the front of the args list to allow
|
||||||
# the recipe to be applied
|
# the recipe to be applied
|
||||||
@ -57,7 +57,7 @@ end
|
|||||||
# user recipes
|
# user recipes
|
||||||
|
|
||||||
|
|
||||||
function _process_userrecipes(plt::Plot, plotattributes::KW, args)
|
@noinline function _process_userrecipes(plt::Plot, plotattributes::KW, args)
|
||||||
still_to_process = RecipeData[]
|
still_to_process = RecipeData[]
|
||||||
args = _preprocess_args(plotattributes, args, still_to_process)
|
args = _preprocess_args(plotattributes, args, still_to_process)
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ function _process_userrecipes(plt::Plot, plotattributes::KW, args)
|
|||||||
kw_list
|
kw_list
|
||||||
end
|
end
|
||||||
|
|
||||||
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
|
@noinline function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
|
||||||
# when the arg tuple is empty, that means there's nothing left to recursively
|
# when the arg tuple is empty, that means there's nothing left to recursively
|
||||||
# process... finish up and add to the kw_list
|
# process... finish up and add to the kw_list
|
||||||
kw = recipedata.plotattributes
|
kw = recipedata.plotattributes
|
||||||
@ -108,7 +108,7 @@ function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeD
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
function _preprocess_userrecipe(kw::KW)
|
@noinline function _preprocess_userrecipe(kw::KW)
|
||||||
_add_markershape(kw)
|
_add_markershape(kw)
|
||||||
|
|
||||||
# if there was a grouping, filter the data here
|
# if there was a grouping, filter the data here
|
||||||
@ -132,7 +132,7 @@ function _preprocess_userrecipe(kw::KW)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
|
@noinline function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
|
||||||
# handle error bars by creating new recipedata data... these will have
|
# handle error bars by creating new recipedata data... these will have
|
||||||
# the same recipedata index as the recipedata they are copied from
|
# the same recipedata index as the recipedata they are copied from
|
||||||
for esym in (:xerror, :yerror)
|
for esym in (:xerror, :yerror)
|
||||||
@ -147,7 +147,7 @@ function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
|
@noinline function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
|
||||||
# handle smoothing by adding a new series
|
# handle smoothing by adding a new series
|
||||||
if get(kw, :smooth, false)
|
if get(kw, :smooth, false)
|
||||||
x, y = kw[:x], kw[:y]
|
x, y = kw[:x], kw[:y]
|
||||||
@ -203,7 +203,7 @@ end
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# setup plot and subplot
|
# setup plot and subplot
|
||||||
|
|
||||||
function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
function _plot_setup(plt::Plot{T}, plotattributes::KW, kw_list::Vector{KW}) where {T}
|
||||||
# merge in anything meant for the Plot
|
# merge in anything meant for the Plot
|
||||||
for kw in kw_list, (k,v) in kw
|
for kw in kw_list, (k,v) in kw
|
||||||
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
|
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
|
||||||
@ -252,18 +252,17 @@ function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
|||||||
plt[:inset_subplots] = nothing
|
plt[:inset_subplots] = nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
function _subplot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
function _subplot_setup(plt::Plot{T}, plotattributes::KW, kw_list::Vector{KW}) where T
|
||||||
# we'll keep a map of subplot to an attribute override dict.
|
# we'll keep a map of subplot to an attribute override dict.
|
||||||
# Subplot/Axis attributes set by a user/series recipe apply only to the
|
# Subplot/Axis attributes set by a user/series recipe apply only to the
|
||||||
# Subplot object which they belong to.
|
# Subplot object which they belong to.
|
||||||
# TODO: allow matrices to still apply to all subplots
|
# TODO: allow matrices to still apply to all subplots
|
||||||
sp_attrs = Dict{Subplot,Any}()
|
sp_attrs = Dict{Any,Any}()
|
||||||
for kw in kw_list
|
for kw in kw_list
|
||||||
# get the Subplot object to which the series belongs.
|
# get the Subplot object to which the series belongs.
|
||||||
sps = get(kw, :subplot, :auto)
|
sps = get(kw, :subplot, :auto)
|
||||||
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
|
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
|
||||||
kw[:subplot] = sp
|
kw[:subplot] = sp
|
||||||
|
|
||||||
# extract subplot/axis attributes from kw and add to sp_attr
|
# extract subplot/axis attributes from kw and add to sp_attr
|
||||||
attr = KW()
|
attr = KW()
|
||||||
for (k,v) in collect(kw)
|
for (k,v) in collect(kw)
|
||||||
@ -303,7 +302,7 @@ end
|
|||||||
|
|
||||||
# getting ready to add the series... last update to subplot from anything
|
# getting ready to add the series... last update to subplot from anything
|
||||||
# that might have been added during series recipes
|
# that might have been added during series recipes
|
||||||
function _prepare_subplot(plt::Plot{T}, plotattributes::KW) where T
|
@noinline function _prepare_subplot(plt::Plot{T}, plotattributes::KW) where T
|
||||||
st::Symbol = plotattributes[:seriestype]
|
st::Symbol = plotattributes[:seriestype]
|
||||||
sp::Subplot{T} = plotattributes[:subplot]
|
sp::Subplot{T} = plotattributes[:subplot]
|
||||||
sp_idx = get_subplot_index(plt, sp)
|
sp_idx = get_subplot_index(plt, sp)
|
||||||
@ -327,7 +326,7 @@ end
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# series types
|
# series types
|
||||||
|
|
||||||
function _override_seriestype_check(plotattributes::KW, st::Symbol)
|
@noinline function _override_seriestype_check(plotattributes::KW, st::Symbol)
|
||||||
# do we want to override the series type?
|
# do we want to override the series type?
|
||||||
if !is3d(st) && !(st in (:contour,:contour3d))
|
if !is3d(st) && !(st in (:contour,:contour3d))
|
||||||
z = plotattributes[:z]
|
z = plotattributes[:z]
|
||||||
@ -339,7 +338,7 @@ function _override_seriestype_check(plotattributes::KW, st::Symbol)
|
|||||||
st
|
st
|
||||||
end
|
end
|
||||||
|
|
||||||
function _prepare_annotations(sp::Subplot, plotattributes::KW)
|
@noinline function _prepare_annotations(sp::Subplot, plotattributes::KW)
|
||||||
# strip out series annotations (those which are based on series x/y coords)
|
# strip out series annotations (those which are based on series x/y coords)
|
||||||
# and add them to the subplot attr
|
# and add them to the subplot attr
|
||||||
sp_anns = annotations(sp[:annotations])
|
sp_anns = annotations(sp[:annotations])
|
||||||
@ -372,7 +371,7 @@ function _expand_subplot_extrema(sp::Subplot, plotattributes::KW, st::Symbol)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _add_the_series(plt, sp, plotattributes)
|
@noinline function _add_the_series(plt, sp, plotattributes)
|
||||||
warnOnUnsupported_args(plt.backend, plotattributes)
|
warnOnUnsupported_args(plt.backend, plotattributes)
|
||||||
warnOnUnsupported(plt.backend, plotattributes)
|
warnOnUnsupported(plt.backend, plotattributes)
|
||||||
series = Series(plotattributes)
|
series = Series(plotattributes)
|
||||||
|
|||||||
37
src/plot.jl
37
src/plot.jl
@ -4,19 +4,19 @@ mutable struct CurrentPlot
|
|||||||
end
|
end
|
||||||
const CURRENT_PLOT = CurrentPlot(nothing)
|
const CURRENT_PLOT = CurrentPlot(nothing)
|
||||||
|
|
||||||
isplotnull() = CURRENT_PLOT.nullableplot === nothing
|
@noinline isplotnull() = CURRENT_PLOT.nullableplot === nothing
|
||||||
|
|
||||||
"""
|
"""
|
||||||
current()
|
current()
|
||||||
Returns the Plot object for the current plot
|
Returns the Plot object for the current plot
|
||||||
"""
|
"""
|
||||||
function current()
|
@noinline function current()
|
||||||
if isplotnull()
|
if isplotnull()
|
||||||
error("No current plot/subplot")
|
error("No current plot/subplot")
|
||||||
end
|
end
|
||||||
CURRENT_PLOT.nullableplot
|
CURRENT_PLOT.nullableplot
|
||||||
end
|
end
|
||||||
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
|
@noinline current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
@ -25,9 +25,9 @@ Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}"
|
|||||||
Base.print(io::IO, plt::Plot) = print(io, string(plt))
|
Base.print(io::IO, plt::Plot) = print(io, string(plt))
|
||||||
Base.show(io::IO, plt::Plot) = print(io, string(plt))
|
Base.show(io::IO, plt::Plot) = print(io, string(plt))
|
||||||
|
|
||||||
getplot(plt::Plot) = plt
|
@noinline getplot(plt::Plot) = plt
|
||||||
getattr(plt::Plot, idx::Int = 1) = plt.attr
|
@noinline getattr(plt::Plot, idx::Int = 1) = plt.attr
|
||||||
convertSeriesIndex(plt::Plot, n::Int) = n
|
@noinline convertSeriesIndex(plt::Plot, n::Int) = n
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
@ -50,11 +50,10 @@ function plot(args...; kw...)
|
|||||||
# this creates a new plot with args/kw and sets it to be the current plot
|
# this creates a new plot with args/kw and sets it to be the current plot
|
||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocessArgs!(plotattributes)
|
||||||
|
|
||||||
# create an empty Plot then process
|
# create an empty Plot then process
|
||||||
plt = Plot()
|
plt = Plot()
|
||||||
# plt.user_attr = plotattributes
|
# plt.user_attr = plotattributes
|
||||||
_plot!(plt, plotattributes, args)
|
_plot!(plt, plotattributes, Any[args...])
|
||||||
end
|
end
|
||||||
|
|
||||||
# build a new plot from existing plots
|
# build a new plot from existing plots
|
||||||
@ -155,7 +154,7 @@ function plot!(plt::Plot, args...; kw...)
|
|||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocessArgs!(plotattributes)
|
||||||
# merge!(plt.user_attr, plotattributes)
|
# merge!(plt.user_attr, plotattributes)
|
||||||
_plot!(plt, plotattributes, args)
|
_plot!(plt, plotattributes, Any[args...])
|
||||||
end
|
end
|
||||||
|
|
||||||
# -------------------------------------------------------------------------------
|
# -------------------------------------------------------------------------------
|
||||||
@ -163,9 +162,10 @@ end
|
|||||||
# this is the core plotting function. recursively apply recipes to build
|
# this is the core plotting function. recursively apply recipes to build
|
||||||
# a list of series KW dicts.
|
# a list of series KW dicts.
|
||||||
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
|
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
|
||||||
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
function _plot!(plt::Plot{T}, plotattributes::KW, args::Vector{Any}) where {T}
|
||||||
plotattributes[:plot_object] = plt
|
plotattributes[:plot_object] = plt
|
||||||
|
|
||||||
|
|
||||||
if !isempty(args) && !isdefined(Main, :StatsPlots) &&
|
if !isempty(args) && !isdefined(Main, :StatsPlots) &&
|
||||||
first(split(string(typeof(args[1])), ".")) == "DataFrames"
|
first(split(string(typeof(args[1])), ".")) == "DataFrames"
|
||||||
@warn("You're trying to plot a DataFrame, but this functionality is provided by StatsPlots")
|
@warn("You're trying to plot a DataFrame, but this functionality is provided by StatsPlots")
|
||||||
@ -175,6 +175,7 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
|||||||
# "USER RECIPES"
|
# "USER RECIPES"
|
||||||
# --------------------------------
|
# --------------------------------
|
||||||
|
|
||||||
|
# 1 second
|
||||||
kw_list = _process_userrecipes(plt, plotattributes, args)
|
kw_list = _process_userrecipes(plt, plotattributes, args)
|
||||||
|
|
||||||
# @info(1)
|
# @info(1)
|
||||||
@ -189,6 +190,7 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
|||||||
# the plot layout is created, which allows for setting layouts and other plot-wide attributes.
|
# the plot layout is created, which allows for setting layouts and other plot-wide attributes.
|
||||||
# we get inputs which have been fully processed by "user recipes" and "type recipes",
|
# we get inputs which have been fully processed by "user recipes" and "type recipes",
|
||||||
# so we can expect standard vectors, surfaces, etc. No defaults have been set yet.
|
# so we can expect standard vectors, surfaces, etc. No defaults have been set yet.
|
||||||
|
|
||||||
still_to_process = kw_list
|
still_to_process = kw_list
|
||||||
kw_list = KW[]
|
kw_list = KW[]
|
||||||
while !isempty(still_to_process)
|
while !isempty(still_to_process)
|
||||||
@ -202,7 +204,11 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
|||||||
# --------------------------------
|
# --------------------------------
|
||||||
# Plot/Subplot/Layout setup
|
# Plot/Subplot/Layout setup
|
||||||
# --------------------------------
|
# --------------------------------
|
||||||
|
|
||||||
|
# 2.5 seconds
|
||||||
_plot_setup(plt, plotattributes, kw_list)
|
_plot_setup(plt, plotattributes, kw_list)
|
||||||
|
|
||||||
|
# 6 seconds
|
||||||
_subplot_setup(plt, plotattributes, kw_list)
|
_subplot_setup(plt, plotattributes, kw_list)
|
||||||
|
|
||||||
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
|
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
|
||||||
@ -216,7 +222,7 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
|||||||
# map(DD, kw_list)
|
# map(DD, kw_list)
|
||||||
|
|
||||||
for kw in kw_list
|
for kw in kw_list
|
||||||
sp::Subplot = kw[:subplot]
|
sp::Subplot{T} = kw[:subplot]
|
||||||
# idx = get_subplot_index(plt, sp)
|
# idx = get_subplot_index(plt, sp)
|
||||||
|
|
||||||
# # we update subplot args in case something like the color palatte is part of the recipe
|
# # we update subplot args in case something like the color palatte is part of the recipe
|
||||||
@ -233,9 +239,9 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
|||||||
# be able to support step, bar, and histogram plots (and any recipes that use those components).
|
# be able to support step, bar, and histogram plots (and any recipes that use those components).
|
||||||
_process_seriesrecipe(plt, kw)
|
_process_seriesrecipe(plt, kw)
|
||||||
end
|
end
|
||||||
|
|
||||||
# --------------------------------
|
# --------------------------------
|
||||||
|
|
||||||
|
# 7 seconds
|
||||||
current(plt)
|
current(plt)
|
||||||
|
|
||||||
# do we want to force display?
|
# do we want to force display?
|
||||||
@ -243,14 +249,14 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
|||||||
# gui(plt)
|
# gui(plt)
|
||||||
# end
|
# end
|
||||||
_do_plot_show(plt, plt[:show])
|
_do_plot_show(plt, plt[:show])
|
||||||
|
|
||||||
plt
|
plt
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# we're getting ready to display/output. prep for layout calcs, then update
|
# we're getting ready to display/output. prep for layout calcs, then update
|
||||||
# the plot object after
|
# the plot object after
|
||||||
function prepare_output(plt::Plot)
|
@noinline function prepare_output(plt::Plot)
|
||||||
|
|
||||||
_before_layout_calcs(plt)
|
_before_layout_calcs(plt)
|
||||||
|
|
||||||
w, h = plt.attr[:size]
|
w, h = plt.attr[:size]
|
||||||
@ -271,9 +277,10 @@ function prepare_output(plt::Plot)
|
|||||||
|
|
||||||
# the backend callback, to reposition subplots, etc
|
# the backend callback, to reposition subplots, etc
|
||||||
_update_plot_object(plt)
|
_update_plot_object(plt)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function backend_object(plt::Plot)
|
@noinline function backend_object(plt::Plot)
|
||||||
prepare_output(plt)
|
prepare_output(plt)
|
||||||
plt.o
|
plt.o
|
||||||
end
|
end
|
||||||
|
|||||||
@ -143,7 +143,7 @@ struct SliceIt end
|
|||||||
rib = ribbons[mod1(i,mr)]
|
rib = ribbons[mod1(i,mr)]
|
||||||
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
|
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
|
||||||
|
|
||||||
push!(series_list, RecipeData(di, ()))
|
push!(series_list, RecipeData(di, Any[]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
nothing # don't add a series for the main block
|
nothing # don't add a series for the main block
|
||||||
|
|||||||
28
src/types.jl
28
src/types.jl
@ -31,11 +31,11 @@ attr!(series::Series, v, k::Symbol) = (series.plotattributes[k] = v)
|
|||||||
|
|
||||||
# a single subplot
|
# a single subplot
|
||||||
mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
|
mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
|
||||||
parent::AbstractLayout
|
parent
|
||||||
series_list::Vector{Series} # arguments for each series
|
series_list::Vector{Series} # arguments for each series
|
||||||
minpad::Tuple # leftpad, toppad, rightpad, bottompad
|
minpad::Tuple{AbsoluteLength,AbsoluteLength,AbsoluteLength,AbsoluteLength} # leftpad, toppad, rightpad, bottompad
|
||||||
bbox::BoundingBox # the canvas area which is available to this subplot
|
bbox#::BoundingBox # the canvas area which is available to this subplot
|
||||||
plotarea::BoundingBox # the part where the data goes
|
plotarea#::BoundingBox # the part where the data goes
|
||||||
attr::KW # args specific to this subplot
|
attr::KW # args specific to this subplot
|
||||||
o # can store backend-specific data... like a pyplot ax
|
o # can store backend-specific data... like a pyplot ax
|
||||||
plt # the enclosing Plot object (can't give it a type because of no forward declarations)
|
plt # the enclosing Plot object (can't give it a type because of no forward declarations)
|
||||||
@ -59,10 +59,6 @@ Extrema() = Extrema(Inf, -Inf)
|
|||||||
|
|
||||||
# -----------------------------------------------------------
|
# -----------------------------------------------------------
|
||||||
|
|
||||||
const SubplotMap = Dict{Any, Subplot}
|
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||||
backend::T # the backend type
|
backend::T # the backend type
|
||||||
@ -71,17 +67,17 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
|||||||
user_attr::KW # raw arg inputs (after aliases). these are used as the input dict in `_plot!`
|
user_attr::KW # raw arg inputs (after aliases). these are used as the input dict in `_plot!`
|
||||||
series_list::Vector{Series} # arguments for each series
|
series_list::Vector{Series} # arguments for each series
|
||||||
o # the backend's plot object
|
o # the backend's plot object
|
||||||
subplots::Vector{Subplot}
|
subplots::Vector{Subplot{T}}
|
||||||
spmap::SubplotMap # provide any label as a map to a subplot
|
spmap::KW # provide any label as a map to a subplot
|
||||||
layout::AbstractLayout
|
layout
|
||||||
inset_subplots::Vector{Subplot} # list of inset subplots
|
inset_subplots::Vector{Subplot{T}} # list of inset subplots
|
||||||
init::Bool
|
init::Bool
|
||||||
end
|
end
|
||||||
|
|
||||||
function Plot()
|
function Plot(_backend = CURRENT_BACKEND)
|
||||||
Plot(backend(), 0, KW(), KW(), Series[], nothing,
|
Plot(_backend.pkg, 0, KW(), KW(), Series[], nothing,
|
||||||
Subplot[], SubplotMap(), EmptyLayout(),
|
Subplot{typeof(_backend.pkg)}[], KW(), EmptyLayout(),
|
||||||
Subplot[], false)
|
Subplot{typeof(_backend.pkg)}[], false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user