diff --git a/src/args.jl b/src/args.jl index 9d718559..502e31e3 100644 --- a/src/args.jl +++ b/src/args.jl @@ -113,118 +113,114 @@ const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt] # ----------------------------------------------------------------------------- -const _seriesDefaults = KW() +const _series_defaults = KW() # series-specific -_seriesDefaults[:axis] = :left -_seriesDefaults[:label] = "AUTO" -_seriesDefaults[:seriescolor] = :auto -_seriesDefaults[:seriesalpha] = nothing -_seriesDefaults[:seriestype] = :path -_seriesDefaults[:linestyle] = :solid -_seriesDefaults[:linewidth] = :auto -_seriesDefaults[:linecolor] = :match -_seriesDefaults[:linealpha] = nothing -_seriesDefaults[:fillrange] = nothing # ribbons, areas, etc -_seriesDefaults[:fillcolor] = :match -_seriesDefaults[:fillalpha] = nothing -_seriesDefaults[:markershape] = :none -_seriesDefaults[:markercolor] = :match -_seriesDefaults[:markeralpha] = nothing -_seriesDefaults[:markersize] = 6 -_seriesDefaults[:markerstrokestyle] = :solid -_seriesDefaults[:markerstrokewidth] = 1 -_seriesDefaults[:markerstrokecolor] = :match -_seriesDefaults[:markerstrokealpha] = nothing -_seriesDefaults[:bins] = 30 # number of bins for hists -_seriesDefaults[:smooth] = false # regression line? -_seriesDefaults[:group] = nothing # groupby vector -_seriesDefaults[:x] = nothing -_seriesDefaults[:y] = nothing -_seriesDefaults[:z] = nothing # depth for contour, surface, etc -_seriesDefaults[:marker_z] = nothing # value for color scale -_seriesDefaults[:levels] = 15 -_seriesDefaults[:orientation] = :vertical -_seriesDefaults[:bar_position] = :overlay # for bar plots and histograms: could also be stack (stack up) or dodge (side by side) -_seriesDefaults[:xerror] = nothing -_seriesDefaults[:yerror] = nothing -_seriesDefaults[:ribbon] = nothing -_seriesDefaults[:quiver] = nothing -_seriesDefaults[:arrow] = nothing # allows for adding arrows to line/path... call `arrow(args...)` -_seriesDefaults[:normalize] = false # do we want a normalized histogram? -_seriesDefaults[:weights] = nothing # optional weights for histograms (1D and 2D) -_seriesDefaults[:contours] = false # add contours to 3d surface and wireframe plots -_seriesDefaults[:match_dimensions] = false # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196 +_series_defaults[:axis] = :left +_series_defaults[:label] = "AUTO" +_series_defaults[:seriescolor] = :auto +_series_defaults[:seriesalpha] = nothing +_series_defaults[:seriestype] = :path +_series_defaults[:linestyle] = :solid +_series_defaults[:linewidth] = :auto +_series_defaults[:linecolor] = :match +_series_defaults[:linealpha] = nothing +_series_defaults[:fillrange] = nothing # ribbons, areas, etc +_series_defaults[:fillcolor] = :match +_series_defaults[:fillalpha] = nothing +_series_defaults[:markershape] = :none +_series_defaults[:markercolor] = :match +_series_defaults[:markeralpha] = nothing +_series_defaults[:markersize] = 6 +_series_defaults[:markerstrokestyle] = :solid +_series_defaults[:markerstrokewidth] = 1 +_series_defaults[:markerstrokecolor] = :match +_series_defaults[:markerstrokealpha] = nothing +_series_defaults[:bins] = 30 # number of bins for hists +_series_defaults[:smooth] = false # regression line? +_series_defaults[:group] = nothing # groupby vector +_series_defaults[:x] = nothing +_series_defaults[:y] = nothing +_series_defaults[:z] = nothing # depth for contour, surface, etc +_series_defaults[:marker_z] = nothing # value for color scale +_series_defaults[:levels] = 15 +_series_defaults[:orientation] = :vertical +_series_defaults[:bar_position] = :overlay # for bar plots and histograms: could also be stack (stack up) or dodge (side by side) +_series_defaults[:xerror] = nothing +_series_defaults[:yerror] = nothing +_series_defaults[:ribbon] = nothing +_series_defaults[:quiver] = nothing +_series_defaults[:arrow] = nothing # allows for adding arrows to line/path... call `arrow(args...)` +_series_defaults[:normalize] = false # do we want a normalized histogram? +_series_defaults[:weights] = nothing # optional weights for histograms (1D and 2D) +_series_defaults[:contours] = false # add contours to 3d surface and wireframe plots +_series_defaults[:match_dimensions] = false # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196 # this ONLY effects whether or not the z-matrix is transposed for a heatmap display! -_seriesDefaults[:subplot] = :auto +_series_defaults[:subplot] = :auto # which subplot(s) does this series belong to? -const _plotDefaults = KW() +const _plot_defaults = KW() -# plot globals -_plotDefaults[:title] = "" -_plotDefaults[:xlabel] = "" -_plotDefaults[:ylabel] = "" -_plotDefaults[:zlabel] = "" -_plotDefaults[:yrightlabel] = "" -_plotDefaults[:legend] = :best -_plotDefaults[:colorbar] = :legend -_plotDefaults[:background_color] = colorant"white" # default for all backgrounds -_plotDefaults[:background_color_legend] = :match # background of legend -_plotDefaults[:background_color_inside] = :match # background inside grid -_plotDefaults[:background_color_outside] = :match # background outside grid -_plotDefaults[:foreground_color] = :auto # default for all foregrounds -_plotDefaults[:foreground_color_legend] = :match # foreground of legend -_plotDefaults[:foreground_color_grid] = :match # grid color -_plotDefaults[:foreground_color_axis] = :match # axis border/tick colors -_plotDefaults[:foreground_color_border] = :match # plot area border/spines -_plotDefaults[:foreground_color_text] = :match # tick text color -_plotDefaults[:foreground_color_guide] = :match # guide text color -_plotDefaults[:xlims] = :auto -_plotDefaults[:ylims] = :auto -_plotDefaults[:zlims] = :auto -_plotDefaults[:xticks] = :auto -_plotDefaults[:yticks] = :auto -_plotDefaults[:zticks] = :auto -_plotDefaults[:xscale] = :identity -_plotDefaults[:yscale] = :identity -_plotDefaults[:zscale] = :identity -_plotDefaults[:xrotation] = 0 -_plotDefaults[:yrotation] = 0 -_plotDefaults[:zrotation] = 0 -_plotDefaults[:xflip] = false -_plotDefaults[:yflip] = false -_plotDefaults[:zflip] = false -_plotDefaults[:size] = (600,400) -_plotDefaults[:pos] = (0,0) -_plotDefaults[:windowtitle] = "Plots.jl" -_plotDefaults[:show] = false -_plotDefaults[:layout] = :auto -_plotDefaults[:n] = -1 -_plotDefaults[:nr] = -1 -_plotDefaults[:nc] = -1 -_plotDefaults[:color_palette] = :auto -_plotDefaults[:link] = false -_plotDefaults[:linkx] = false -_plotDefaults[:linky] = false -_plotDefaults[:linkfunc] = nothing -_plotDefaults[:tickfont] = font(8) -_plotDefaults[:guidefont] = font(11) -_plotDefaults[:legendfont] = font(8) -_plotDefaults[:grid] = true -_plotDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation) -_plotDefaults[:overwrite_figure] = false -_plotDefaults[:polar] = false -_plotDefaults[:aspect_ratio] = :none # choose from :none or :equal -_plotDefaults[:xaxis] = xaxis() -_plotDefaults[:yaxis] = yaxis() -_plotDefaults[:zaxis] = zaxis() +_plot_defaults[:title] = "" +_plot_defaults[:legend] = :best +_plot_defaults[:colorbar] = :legend +_plot_defaults[:background_color] = colorant"white" # default for all backgrounds +_plot_defaults[:background_color_outside] = :match # background outside grid +_plot_defaults[:foreground_color] = :auto # default for all foregrounds +_plot_defaults[:size] = (600,400) +_plot_defaults[:pos] = (0,0) +_plot_defaults[:windowtitle] = "Plots.jl" +_plot_defaults[:show] = false +_plot_defaults[:layout] = :auto +_plot_defaults[:num_subplots] = -1 +_plot_defaults[:num_rows] = -1 +_plot_defaults[:num_cols] = -1 +_plot_defaults[:color_palette] = :auto +_plot_defaults[:link] = false +_plot_defaults[:linkx] = false +_plot_defaults[:linky] = false +_plot_defaults[:linkfunc] = nothing +_plot_defaults[:overwrite_figure] = false -# TODO: x/y scales +const _subplot_defaults = KW() -const _allArgs = sort(collect(union(keys(_seriesDefaults), keys(_plotDefaults)))) -supportedArgs(::AbstractBackend) = error("supportedArgs not defined") #_allArgs +_subplot_defaults[:title] = "" +_subplot_defaults[:background_color_legend] = :match # background of legend +_subplot_defaults[:background_color_inside] = :match # background inside grid +_subplot_defaults[:foreground_color_legend] = :match # foreground of legend +_subplot_defaults[:foreground_color_grid] = :match # grid color +_subplot_defaults[:legendfont] = font(8) +_subplot_defaults[:grid] = true +_subplot_defaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation) +_subplot_defaults[:polar] = false +_subplot_defaults[:aspect_ratio] = :none # choose from :none or :equal + +const _axis_defaults = KW() + +_axis_defaults[:label] = :auto +_axis_defaults[:xlims] = :auto +_axis_defaults[:xticks] = :auto +_axis_defaults[:xscale] = :identity +_axis_defaults[:xrotation] = 0 +_axis_defaults[:xflip] = false +# _axis_defaults[:axis] = :auto +_axis_defaults[:tickfont] = font(8) +_axis_defaults[:guidefont] = font(11) +_axis_defaults[:foreground_color_axis] = :match # axis border/tick colors +_axis_defaults[:foreground_color_border] = :match # plot area border/spines +_axis_defaults[:foreground_color_text] = :match # tick text color +_axis_defaults[:foreground_color_guide] = :match # guide text color + +const _all_defaults = KW[ + _series_defaults, + _plot_defaults, + _subplot_defaults, + _axis_defaults +] + +const _all_args = sort(collect(union(map(keys, _all_defaults)...))) +supportedArgs(::AbstractBackend) = error("supportedArgs not defined") #_all_args supportedArgs() = supportedArgs(backend()) RecipesBase.is_key_supported(k::Symbol) = (k in supportedArgs()) @@ -342,8 +338,9 @@ add_aliases(:show, :gui, :display) add_aliases(:color_palette, :palette) add_aliases(:linkx, :xlink) add_aliases(:linky, :ylink) -add_aliases(:nr, :nrow, :nrows, :rows) -add_aliases(:nc, :ncol, :ncols, :cols, :ncolumns, :columns) +add_aliases(:num_subplots, :n, :numplots, :nplts) +add_aliases(:num_rows, :nr, :nrow, :nrows, :rows) +add_aliases(:num_cols, :nc, :ncol, :ncols, :cols, :ncolumns, :columns) add_aliases(:overwrite_figure, :clf, :clearfig, :overwrite, :reuse) add_aliases(:xerror, :xerr, :xerrorbar) add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar) @@ -354,7 +351,7 @@ add_aliases(:match_dimensions, :transpose, :transpose_z) # add all pluralized forms to the _keyAliases dict -for arg in keys(_seriesDefaults) +for arg in keys(_series_defaults) _keyAliases[makeplural(arg)] = arg end @@ -372,24 +369,37 @@ end function default(k::Symbol) k = get(_keyAliases, k, k) - if haskey(_seriesDefaults, k) - return _seriesDefaults[k] - elseif haskey(_plotDefaults, k) - return _plotDefaults[k] - else - error("Unknown key: ", k) + for defaults in _all_defaults + if haskey(defaults, k) + return defaults[k] + end end + error("Unknown key: ", k) + # if haskey(_series_defaults, k) + # return _series_defaults[k] + # elseif haskey(_plot_defaults, k) + # return _plot_defaults[k] + # else + # error("Unknown key: ", k) + # end end function default(k::Symbol, v) k = get(_keyAliases, k, k) - if haskey(_seriesDefaults, k) - _seriesDefaults[k] = v - elseif haskey(_plotDefaults, k) - _plotDefaults[k] = v - else - error("Unknown key: ", k) + for defaults in _all_defaults + if haskey(defaults, k) + defaults[k] = v + return v + end end + error("Unknown key: ", k) + # if haskey(_series_defaults, k) + # _series_defaults[k] = v + # elseif haskey(_plot_defaults, k) + # _plot_defaults[k] = v + # else + # error("Unknown key: ", k) + # end end function default(; kw...) @@ -801,8 +811,8 @@ function getPlotArgs(pkg::AbstractBackend, kw, idx::Int; set_defaults = true) # add defaults? if set_defaults - for k in keys(_plotDefaults) - setDictValue(kwdict, d, k, idx, _plotDefaults) + for k in keys(_plot_defaults) + setDictValue(kwdict, d, k, idx, _plot_defaults) end end # @@ -839,8 +849,8 @@ end # d = KW() # # # add defaults? -# for k in keys(_seriesDefaults) -# setDictValue(kwdict, d, k, commandIndex, _seriesDefaults) +# for k in keys(_series_defaults) +# setDictValue(kwdict, d, k, commandIndex, _series_defaults) # end # # # groupby args? diff --git a/src/backends/unicodeplots.jl b/src/backends/unicodeplots.jl index d2bd5f3c..07e11daa 100644 --- a/src/backends/unicodeplots.jl +++ b/src/backends/unicodeplots.jl @@ -186,7 +186,7 @@ end function _create_backend_figure(plt::Plot{UnicodePlotsBackend}) # do we want to give a new default size? - if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == _plotDefaults[:size] + if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == default(:size) plt.plotargs[:size] = (60,20) end nothing diff --git a/src/colors.jl b/src/colors.jl index 3ab085fa..388537fd 100644 --- a/src/colors.jl +++ b/src/colors.jl @@ -364,8 +364,8 @@ function handlePlotColors(::AbstractBackend, d::KW) if :background_color in supportedArgs() bgcolor = convertColor(d[:background_color]) else - bgcolor = _plotDefaults[:background_color] - if d[:background_color] != _plotDefaults[:background_color] + bgcolor = default(:background_color) + if d[:background_color] != default(:background_color) warn("Cannot set background_color with backend $(backend())") end end diff --git a/src/components.jl b/src/components.jl index 9e073868..26d7affd 100644 --- a/src/components.jl +++ b/src/components.jl @@ -273,7 +273,7 @@ const _axis_symbols_fonts_colors = ( ) function Axis(letter::AbstractString, args...; kw...) - # init with values from _plotDefaults + # init with values from _plot_defaults d = KW( :letter => letter, :extrema => (Inf, -Inf), @@ -282,13 +282,14 @@ function Axis(letter::AbstractString, args...; kw...) :use_minor => false, :show => true, # show or hide the axis? (useful for linked subplots) ) - for sym in _axis_symbols - k = symbol(letter * string(sym)) - d[sym] = _plotDefaults[k] - end - for k in _axis_symbols_fonts_colors - d[k] = _plotDefaults[k] - end + merge!(d, _axis_defaults) + # for sym in _axis_symbols + # k = symbol(letter * string(sym)) + # d[sym] = _plot_defaults[k] + # end + # for k in _axis_symbols_fonts_colors + # d[k] = _plot_defaults[k] + # end # update the defaults update!(Axis(d), args...; kw...) diff --git a/src/plot.jl b/src/plot.jl index 3f3814ef..9fc125ba 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -94,6 +94,7 @@ function strip_first_letter(s::Symbol) str[1:1], symbol(str[2:end]) end +# TODO: need to apply axis args to the axes, subplot args to the subplots, and plot args to the plot # merge the KW d into the plot args function _add_plotargs!(plt::Plot, d::KW) # @show d @@ -139,7 +140,7 @@ function _add_plotargs!(plt::Plot, d::KW) # @show 4,axis end - for k in keys(_plotDefaults) + for k in keys(_plot_defaults) if haskey(d, k) plt.plotargs[k] = pop!(d, k) end @@ -262,7 +263,7 @@ function _plot!(plt::Plot, d::KW, args...) # !!! note: at this point, kw_list is fully decomposed into individual series... one KW per series !!! - + # TODO: move annotations into subplot update # now include any annotations which were added during recipes for kw in kw_list append!(anns, annotations(pop!(kw, :annotation, []))) @@ -295,28 +296,6 @@ function _plot!(plt::Plot, d::KW, args...) plt.n += 1 end - # TODO: can this be handled as a recipe?? (yes... need to remove) - # note: this could probably be handled using a recipe signature f{S<:Union{AbstractString,Symbol}}(v::AVec{S}, letter::AbstractString) - # that gets called from within the SliceIt section - # if !stringsSupported() && di[:seriestype] != :pie - # setTicksFromStringVector(plt, d, di, "x") - # setTicksFromStringVector(plt, d, di, "y") - # setTicksFromStringVector(plt, d, di, "z") - # end - - # TODO: unnecessary?? (yes... deleted as part of _add_plotargs... remove this) - # # remove plot args - # for k in keys(_plotDefaults) - # delete!(di, k) - # end - - # TODO: why?? (I think we can remove??) - # # merge in plotarg_overrides - # plotarg_overrides = pop!(di, :plotarg_overrides, nothing) - # if plotarg_overrides != nothing - # merge!(plt.plotargs, plotarg_overrides) - # end - # set default values, select from attribute cycles, and generally set the final attributes _add_defaults!(kw, plt, i) @@ -334,12 +313,8 @@ function _plot!(plt::Plot, d::KW, args...) # now that we're done adding all the series, add the annotations _add_annotations(plt, anns) - # add title, axis labels, ticks, etc - # TODO: do we really need this subplot check? - # if !haskey(d, :subplot) - # merge!(plt.plotargs, d) # this shouldn't be needed since we merged the keys earlier - _update_plot(plt, plt.plotargs) - # end + # TODO just need to pass plt... and we should do all non-series updates here + _update_plot(plt, plt.plotargs) current(plt) @@ -411,7 +386,7 @@ end # end # # # remove plot args -# for k in keys(_plotDefaults) +# for k in keys(_plot_defaults) # delete!(di, k) # end # @@ -540,7 +515,7 @@ function Base.copy(plt::Plot) backend(plt.backend) plt2 = plot(; plt.plotargs...) for sargs in plt.seriesargs - sargs = filter((k,v) -> haskey(_seriesDefaults,k), sargs) + sargs = filter((k,v) -> haskey(_series_defaults,k), sargs) plot!(plt2; sargs...) end plt2 diff --git a/src/series_new.jl b/src/series_new.jl index 36d2f2fc..e1b78de2 100644 --- a/src/series_new.jl +++ b/src/series_new.jl @@ -10,8 +10,8 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int) globalIndex = n # add defaults? - for k in keys(_seriesDefaults) - setDictValue(d, d, k, commandIndex, _seriesDefaults) + for k in keys(_series_defaults) + setDictValue(d, d, k, commandIndex, _series_defaults) end if d[:subplot] == :auto diff --git a/src/subplots.jl b/src/subplots.jl index ae21be79..2ad77d7a 100644 --- a/src/subplots.jl +++ b/src/subplots.jl @@ -177,21 +177,47 @@ end # ---------------------------------------------------------------------- # return the top-level layout, a list of subplots, and a SubplotMap -function build_layout(s::Symbol) - s == :auto || error() # TODO: handle anything else - layout = GridLayout(1, 2) #TODO this need to go - nr, nc = size(layout) +function build_layout(d::KW) + l = get(d, :layout, :auto) + n = get(d, :num_subplots, -1) + nr = get(d, :num_rows, -1) + nc = get(d, :num_cols, -1) + + l == :auto || error() # TODO: handle anything else + + nr, nc = compute_gridsize(n, nr, nc) + layout = GridLayout(nr, nc) subplots = Subplot[] spmap = SubplotMap() + i = 1 for r=1:nr, c=1:nc + i > n && break # only add n subplots sp = Subplot(backend(), parent=layout) layout[r,c] = sp push!(subplots, sp) spmap[(r,c)] = sp + i += 1 end layout, subplots, spmap end + + +function compute_gridsize(numplts::Int, nr::Int, nc::Int) + # figure out how many rows/columns we need + if nr == -1 + if nc == -1 + nr = round(Int, sqrt(numplts)) + nc = ceil(Int, numplts / nr) + else + nr = ceil(Int, numplts / nc) + end + else + nc = ceil(Int, numplts / nr) + end + nr, nc +end + # ---------------------------------------------------------------------- get_subplot(plt::Plot, sp::Subplot) = sp diff --git a/src/types.jl b/src/types.jl index f9bd5ea5..16e5d749 100644 --- a/src/types.jl +++ b/src/types.jl @@ -69,7 +69,7 @@ end type Subplot{T<:AbstractBackend} <: AbstractLayout parent::AbstractLayout bbox::BoundingBox # the canvas area which is available to this subplot - attr::KW # args specific to this subplot + subplotargs::KW # args specific to this subplot # axisviews::Vector{AxisView} o # can store backend-specific data... like a pyplot ax diff --git a/src/utils.jl b/src/utils.jl index e99187c6..ae6ef516 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -614,7 +614,7 @@ function supportGraph(allvals, func) aspect_ratio = :equal) end -supportGraphArgs() = supportGraph(_allArgs, supportedArgs) +supportGraphArgs() = supportGraph(_all_args, supportedArgs) supportGraphTypes() = supportGraph(_allTypes, supportedTypes) supportGraphStyles() = supportGraph(_allStyles, supportedStyles) supportGraphMarkers() = supportGraph(_allMarkers, supportedMarkers)