From 327f235af949bf2e3ebd390cd95625fd75a92c22 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 18 May 2016 14:08:44 -0400 Subject: [PATCH] working on subplot/axis arg processing --- src/Plots.jl | 1 + src/args.jl | 115 +++++++++++++++++++++++++++-------- src/backends/bokeh.jl | 4 +- src/backends/gadfly.jl | 14 ++--- src/backends/glvisualize.jl | 4 +- src/backends/gr.jl | 16 ++--- src/backends/pgfplots.jl | 6 +- src/backends/plotly.jl | 6 +- src/backends/plotlyjs.jl | 4 +- src/backends/pyplot.jl | 19 ++++-- src/backends/qwt.jl | 8 +-- src/backends/unicodeplots.jl | 10 +-- src/backends/winston.jl | 10 +-- src/components.jl | 6 +- src/old_subplot.jl | 4 +- src/plot.jl | 29 ++++++--- src/series_new.jl | 6 +- src/subplots.jl | 70 ++++++++++++++++++--- src/utils.jl | 1 + 19 files changed, 240 insertions(+), 93 deletions(-) diff --git a/src/Plots.jl b/src/Plots.jl index 267889f9..66e31bca 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -292,6 +292,7 @@ function __init__() setup_ijulia() # setup_dataframes() setup_atom() + # add_axis_letter_defaults() end # --------------------------------------------------------- diff --git a/src/args.jl b/src/args.jl index 6b5d08b7..93803a25 100644 --- a/src/args.jl +++ b/src/args.jl @@ -170,15 +170,15 @@ _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[:layout] = 1 +# _plot_defaults[:num_subplots] = -1 +# _plot_defaults[:num_rows] = -1 +# _plot_defaults[:num_cols] = -1 _plot_defaults[:link] = false _plot_defaults[:linkx] = false _plot_defaults[:linky] = false _plot_defaults[:linkfunc] = nothing -_plot_defaults[:overwrite_figure] = false +_plot_defaults[:overwrite_figure] = true const _subplot_defaults = KW() @@ -196,12 +196,13 @@ _subplot_defaults[:colorbar] = :legend _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[:polar] = false +_subplot_defaults[:projection] = :none # can also be :polar or :3d _subplot_defaults[:aspect_ratio] = :none # choose from :none or :equal const _axis_defaults = KW() -_axis_defaults[:label] = "" +_axis_defaults[:guide] = "" _axis_defaults[:lims] = :auto _axis_defaults[:ticks] = :auto _axis_defaults[:scale] = :identity @@ -214,11 +215,36 @@ _axis_defaults[:foreground_color_border] = :match # plot area border/ _axis_defaults[:foreground_color_text] = :match # tick text color _axis_defaults[:foreground_color_guide] = :match # guide text color +# add defaults for the letter versions +const _axis_defaults_byletter = KW() +for letter in (:x,:y,:z) + for k in (:guide, + :lims, + :ticks, + :scale, + :rotation, + :flip, + :tickfont, + :guidefont, + :foreground_color_axis, + :foreground_color_border, + :foreground_color_text, + :foreground_color_guide) + _axis_defaults_byletter[symbol(letter,k)] = nothing + end +end +@show _axis_defaults +# for letter in (:x, :y, :z) +# for (k,v) in _axis_defaults +# _axis_defaults[symbol(letter,k)] = v +# end +# end + const _all_defaults = KW[ _series_defaults, _plot_defaults, _subplot_defaults, - _axis_defaults + _axis_defaults_byletter ] const _all_args = sort(collect(union(map(keys, _all_defaults)...))) @@ -315,18 +341,18 @@ add_aliases(:group, :g, :grouping) add_aliases(:bins, :bin, :nbin, :nbins, :nb) add_aliases(:ribbon, :rib) add_aliases(:annotation, :ann, :anns, :annotate, :annotations) -add_aliases(:xlabel, :xlab, :xl) +add_aliases(:xguide, :xlabel, :xlab, :xl) add_aliases(:xlims, :xlim, :xlimit, :xlimits) add_aliases(:xticks, :xtick) add_aliases(:xrotation, :xrot, :xr) -add_aliases(:ylabel, :ylab, :yl) +add_aliases(:xguide, :ylabel, :ylab, :yl) add_aliases(:ylims, :ylim, :ylimit, :ylimits) add_aliases(:yticks, :ytick) -add_aliases(:yrightlabel, :yrlab, :yrl, :ylabel2, :y2label, :ylab2, :y2lab, :ylabr, :ylabelright) -add_aliases(:yrightlims, :yrlim, :yrlimit, :yrlimits) -add_aliases(:yrightticks, :yrtick) +# add_aliases(:yrightlabel, :yrlab, :yrl, :ylabel2, :y2label, :ylab2, :y2lab, :ylabr, :ylabelright) +# add_aliases(:yrightlims, :yrlim, :yrlimit, :yrlimits) +# add_aliases(:yrightticks, :yrtick) add_aliases(:yrotation, :yrot, :yr) -add_aliases(:zlabel, :zlab, :zl) +add_aliases(:zguide, :zlabel, :zlab, :zl) add_aliases(:zlims, :zlim, :zlimit, :zlimits) add_aliases(:zticks, :ztick) add_aliases(:zrotation, :zrot, :zr) @@ -340,9 +366,9 @@ add_aliases(:show, :gui, :display) add_aliases(:color_palette, :palette) add_aliases(:linkx, :xlink) add_aliases(:linky, :ylink) -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(: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) @@ -351,6 +377,7 @@ add_aliases(:normalize, :norm, :normed, :normalized) add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio) add_aliases(:match_dimensions, :transpose, :transpose_z) add_aliases(:subplot, :sp, :subplt, :splt) +add_aliases(:projection, :proj) # add all pluralized forms to the _keyAliases dict @@ -839,13 +866,16 @@ slice_arg(v, idx) = v # given an argument key (k), we want to extract the argument value for this index. # matrices are sliced by column, otherwise we # if nothing is set (or container is empty), return the default or the existing value. -function slice_arg!(d_in::KW, d_out::KW, k::Symbol, default_value, idx::Int = 1) - v = pop!(d_in, k, get(d_out, k, default_value)) - d_out[k] = if haskey(d_in, k) && typeof(v) <: AMat && !isempty(v) +function slice_arg!(d_in::KW, d_out::KW, k::Symbol, default_value, idx::Int = 1; new_key::Symbol = k, remove_pair::Bool = true) + v = get(d_in, k, get(d_out, new_key, default_value)) + d_out[new_key] = if haskey(d_in, k) && typeof(v) <: AMat && !isempty(v) slice_arg(v, idx) else v end + if remove_pair + delete!(d_in, k) + end end # if the value is `:match` then we take whatever match_color is. @@ -882,11 +912,12 @@ end # update a subplots args and axes -function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW) +function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::Integer) pargs = plt.plotargs spargs = sp.subplotargs + # @show subplot_index, sp for (k,v) in _subplot_defaults - slice_arg!(d_in, spargs, k, v) + slice_arg!(d_in, spargs, k, v, subplot_index) end # handle legend/colorbar @@ -907,6 +938,9 @@ function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW) color_or_match!(spargs, :foreground_color_legend, fg) color_or_match!(spargs, :foreground_color_grid, fg) + # info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + # DD(spargs, "before loop") + for letter in (:x, :y, :z) # get (maybe initialize) the axis axissym = symbol(letter, :axis) @@ -917,14 +951,38 @@ function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW) # build the KW of arguments from the letter version (i.e. xticks --> ticks) kw = KW() - for k in _axis_defaults + # DD(d_in, "d_in before") + + for (k,v) in _axis_defaults + # first get the args without the letter: `tickfont = font(10)` + # note: we don't pop because we want this to apply to all axes! (delete after all have finished) + if haskey(d_in, k) + kw[k] = slice_arg(d_in[k], subplot_index) + end + + # then get those args that were passed with a leading letter: `xlabel = "X"` lk = symbol(letter, k) if haskey(d_in, lk) - kw[k] = d_in[lk] + kw[k] = slice_arg(pop!(d_in, lk), subplot_index) end end + # for (k,v) in _axis_defaults + # # first get the args without the letter: `tickfont = font(10)` + # slice_arg!(d_in, kw, k, v, subplot_index) + # + # # then get those args that were passed with a leading letter: `xlabel = "X"` + # lk = symbol(letter, k) + # slice_arg!(d_in, kw, lk, v, subplot_index; new_key = k) + # # if haskey(d_in, lk) + # # kw[k] = d_in[lk] + # # end + # end + # DD(d_in, "d_in after") + # DD(kw, "kw") + # update the axis + # @show args,kw update!(axis, args...; kw...) # update the axis colors @@ -932,7 +990,16 @@ function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW) color_or_match!(axis.d, :foreground_color_border, fg) color_or_match!(axis.d, :foreground_color_guide, fg) color_or_match!(axis.d, :foreground_color_text, fg) + # DD(axis.d, "axis") end + + # now we can get rid of the axis keys without a letter + for k in keys(_axis_defaults) + delete!(d_in, k) + end + + # DD(spargs[:xaxis].d, "after loop") + # info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") end diff --git a/src/backends/bokeh.jl b/src/backends/bokeh.jl index 86ecd847..fd56af91 100644 --- a/src/backends/bokeh.jl +++ b/src/backends/bokeh.jl @@ -39,11 +39,11 @@ supportedArgs(::BokehBackend) = [ :title, # :windowtitle, :x, - # :xlabel, + # :xguide, # :xlims, # :xticks, :y, - # :ylabel, + # :yguide, # :ylims, # :yrightlabel, # :yticks, diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index 2c37516a..af342454 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -13,9 +13,9 @@ supportedArgs(::GadflyBackend) = [ :fillrange, :fillcolor, :fillalpha, :bins, :n, :nc, :nr, :layout, :smooth, :title, :windowtitle, :show, :size, - :x, :xlabel, :xlims, :xticks, :xscale, :xflip, - :y, :ylabel, :ylims, :yticks, :yscale, :yflip, - # :z, :zlabel, :zlims, :zticks, :zscale, :zflip, + :x, :xguide, :xlims, :xticks, :xscale, :xflip, + :y, :yguide, :ylims, :yticks, :yscale, :yflip, + # :z, :zguide, :zlims, :zticks, :zscale, :zflip, :z, :tickfont, :guidefont, :legendfont, :grid, :legend, :colorbar, @@ -59,8 +59,8 @@ function createGadflyPlotObject(d::KW) gplt.data_source = Gadfly.DataFrames.DataFrame() # gplt.layers = gplt.layers[1:0] gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());] - gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]), - Gadfly.Guide.ylabel(d[:ylabel]), + gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xguide]), + Gadfly.Guide.ylabel(d[:yguide]), Gadfly.Guide.title(d[:title])] gplt end @@ -469,8 +469,8 @@ end function updateGadflyGuides(plt::Plot, d::KW) gplt = getGadflyContext(plt) haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title])) - haskey(d, :xlabel) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xlabel])) - haskey(d, :ylabel) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:ylabel])) + haskey(d, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xguide])) + haskey(d, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:yguide])) xlims, xfunc = addGadflyLimitsScale(gplt, d, true) ylims, yfunc = addGadflyLimitsScale(gplt, d, false) diff --git a/src/backends/glvisualize.jl b/src/backends/glvisualize.jl index a8b40243..017ea36b 100644 --- a/src/backends/glvisualize.jl +++ b/src/backends/glvisualize.jl @@ -39,11 +39,11 @@ supportedArgs(::GLVisualizeBackend) = [ # :title, # :windowtitle, # :x, - # :xlabel, + # :xguide, # :xlims, # :xticks, # :y, - # :ylabel, + # :yguide, # :ylims, # :yrightlabel, # :yticks, diff --git a/src/backends/gr.jl b/src/backends/gr.jl index f9c63bbf..1007537f 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -20,10 +20,10 @@ supportedArgs(::GRBackend) = [ :n, :nc, :nr, :layout, :smooth, :title, :windowtitle, :show, :size, - :x, :xlabel, :xlims, :xticks, :xscale, :xflip, - :y, :ylabel, :ylims, :yticks, :yscale, :yflip, + :x, :xguide, :xlims, :xticks, :xscale, :xflip, + :y, :yguide, :ylims, :yticks, :yscale, :yflip, # :axis, :yrightlabel, - :z, :zlabel, :zlims, :zticks, :zscale, :zflip, + :z, :zguide, :zlims, :zticks, :zscale, :zflip, :z, :tickfont, :guidefont, :legendfont, :grid, :legend, :colorbar, @@ -409,19 +409,19 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true, GR.text(0.5 * (viewport[1] + viewport[2]), vp[4], d[:title]) GR.restorestate() end - if get(d, :xlabel, "") != "" + if get(d, :xguide, "") != "" GR.savestate() GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM) GR.settextcolorind(fg) - GR.text(0.5 * (viewport[1] + viewport[2]), vp[3], d[:xlabel]) + GR.text(0.5 * (viewport[1] + viewport[2]), vp[3], d[:xguide]) GR.restorestate() end - if get(d, :ylabel, "") != "" + if get(d, :yguide, "") != "" GR.savestate() GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) GR.setcharup(-1, 0) GR.settextcolorind(fg) - GR.text(vp[1], 0.5 * (viewport[3] + viewport[4]), d[:ylabel]) + GR.text(vp[1], 0.5 * (viewport[3] + viewport[4]), d[:yguide]) GR.restorestate() end # if get(d, :yrightlabel, "") != "" @@ -872,7 +872,7 @@ end # end function _update_plot(plt::Plot{GRBackend}, d::KW) - for k in (:title, :xlabel, :ylabel) + for k in (:title, :xguide, :yguide) haskey(d, k) && (plt.plotargs[k] = d[k]) end end diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl index eda0503b..06e7cc8f 100644 --- a/src/backends/pgfplots.jl +++ b/src/backends/pgfplots.jl @@ -38,11 +38,11 @@ supportedArgs(::PGFPlotsBackend) = [ :title, # :windowtitle, :x, - :xlabel, + :xguide, :xlims, # :xticks, :y, - :ylabel, + :yguide, :ylims, # :yrightlabel, # :yticks, @@ -297,7 +297,7 @@ end function _pgfplots_get_axis_kwargs(d) axisargs = KW() - for arg in (:xlabel, :ylabel, :zlabel, :title) + for arg in (:xguide, :yguide, :zguide, :title) axisargs[arg] = d[arg] end axisargs[:style] = "" diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 54ca1550..7bcbe523 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -19,9 +19,9 @@ supportedArgs(::PlotlyBackend) = [ :n, :nc, :nr, :layout, # :smooth, :title, :windowtitle, :show, :size, - :x, :xlabel, :xlims, :xticks, :xscale, :xflip, :xrotation, - :y, :ylabel, :ylims, :yticks, :yscale, :yflip, :yrotation, - :z, :zlabel, :zlims, :zticks, :zscale, :zflip, :zrotation, + :x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation, + :y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation, + :z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation, :z, :tickfont, :guidefont, :legendfont, :grid, :legend, :colorbar, diff --git a/src/backends/plotlyjs.jl b/src/backends/plotlyjs.jl index 6adc70e2..12d2ba3f 100644 --- a/src/backends/plotlyjs.jl +++ b/src/backends/plotlyjs.jl @@ -38,11 +38,11 @@ supportedArgs(::PlotlyJSBackend) = [ :title, :windowtitle, :x, - :xlabel, + :xguide, :xlims, :xticks, :y, - :ylabel, + :yguide, :ylims, # :yrightlabel, :yticks, diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 84b91f49..080fad29 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -20,10 +20,10 @@ supportedArgs(::PyPlotBackend) = [ :n, :nc, :nr, :layout, :smooth, :title, :windowtitle, :show, :size, - :x, :xlabel, :xlims, :xticks, :xscale, :xflip, :xrotation, - :y, :ylabel, :ylims, :yticks, :yscale, :yflip, :yrotation, + :x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation, + :y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation, # :axis, :yrightlabel, - :z, :zlabel, :zlims, :zticks, :zscale, :zflip, :zrotation, + :z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation, :z, :tickfont, :guidefont, :legendfont, :grid, :legend, :colorbar, @@ -383,7 +383,14 @@ end function _initialize_subplot(plt::Plot{PyPlotBackend}, sp::Subplot{PyPlotBackend}) fig = plt.o # add a new axis, and force it to create a new one by setting a distinct label - ax = fig[:add_axes]([0,0,1,1], label = string(gensym())) + proj = sp.subplotargs[:projection] + ax = fig[:add_axes]( + [0,0,1,1], + label = string(gensym()), + projection = (proj in (nothing,:none) ? nothing : string(proj)) + ) + # projection = + # ax = fig[:add_subplot](111, projection = _py_projections[sp.subplotargs[:projection]]) # for axis in (:xaxis, :yaxis) # ax[axis][:_autolabelpos] = false # end @@ -1130,11 +1137,13 @@ function _update_plot(plt::Plot{PyPlotBackend}, d::KW) axissym = symbol(letter, :axis) axis = spargs[axissym] # @show axis + # DD(axis.d, "updateplot") + # @show haskey(ax, axissym) haskey(ax, axissym) || continue applyPyPlotScale(ax, axis[:scale], letter) addPyPlotLims(ax, axis[:lims], letter) addPyPlotTicks(ax, get_ticks(axis), letter) - ax[symbol("set_", letter, "label")](axis[:label]) + ax[symbol("set_", letter, "label")](axis[:guide]) if get(axis.d, :flip, false) ax[symbol("invert_", letter, "axis")]() end diff --git a/src/backends/qwt.jl b/src/backends/qwt.jl index 87eb6211..0b1cc853 100644 --- a/src/backends/qwt.jl +++ b/src/backends/qwt.jl @@ -33,11 +33,11 @@ supportedArgs(::QwtBackend) = [ :title, :windowtitle, :x, - :xlabel, + :xguide, :xlims, :xticks, :y, - :ylabel, + :yguide, :ylims, :yrightlabel, :yticks, @@ -192,8 +192,8 @@ end function _update_plot(plt::Plot{QwtBackend}, d::KW) haskey(d, :title) && Qwt.title(plt.o, d[:title]) - haskey(d, :xlabel) && Qwt.xlabel(plt.o, d[:xlabel]) - haskey(d, :ylabel) && Qwt.ylabel(plt.o, d[:ylabel]) + haskey(d, :xguide) && Qwt.xlabel(plt.o, d[:xguide]) + haskey(d, :yguide) && Qwt.ylabel(plt.o, d[:yguide]) updateLimsAndTicks(plt, d, true) updateLimsAndTicks(plt, d, false) end diff --git a/src/backends/unicodeplots.jl b/src/backends/unicodeplots.jl index 0d40d64f..aeffb056 100644 --- a/src/backends/unicodeplots.jl +++ b/src/backends/unicodeplots.jl @@ -37,11 +37,11 @@ supportedArgs(::UnicodePlotsBackend) = [ :title, :windowtitle, :x, - :xlabel, + :xguide, :xlims, # :xticks, :y, - :ylabel, + :yguide, :ylims, # :yrightlabel, # :yticks, @@ -116,8 +116,8 @@ function rebuildUnicodePlot!(plt::Plot) ylim = ylim) # set the axis labels - UnicodePlots.xlabel!(o, iargs[:xlabel]) - UnicodePlots.ylabel!(o, iargs[:ylabel]) + UnicodePlots.xlabel!(o, iargs[:xguide]) + UnicodePlots.ylabel!(o, iargs[:yguide]) # now use the ! functions to add to the plot for d in sargs @@ -209,7 +209,7 @@ end function _update_plot(plt::Plot{UnicodePlotsBackend}, d::KW) - for k in (:title, :xlabel, :ylabel, :xlims, :ylims) + for k in (:title, :xguide, :yguide, :xlims, :ylims) if haskey(d, k) plt.plotargs[k] = d[k] end diff --git a/src/backends/winston.jl b/src/backends/winston.jl index 6b90b457..6229923f 100644 --- a/src/backends/winston.jl +++ b/src/backends/winston.jl @@ -41,11 +41,11 @@ supportedArgs(::WinstonBackend) = [ :title, :windowtitle, :x, - :xlabel, + :xguide, :xlims, # :xticks, :y, - :ylabel, + :yguide, :ylims, # :yrightlabel, # :yticks, @@ -105,8 +105,8 @@ end function _create_backend_figure(plt::Plot{WinstonBackend}) Winston.FramedPlot( title = plt.plotargs[:title], - xlabel = plt.plotargs[:xlabel], - ylabel = plt.plotargs[:ylabel] + xlabel = plt.plotargs[:xguide], + ylabel = plt.plotargs[:yguide] ) end @@ -229,7 +229,7 @@ end function _update_plot(plt::Plot{WinstonBackend}, d::KW) window, canvas, wplt = getWinstonItems(plt) - for k in (:xlabel, :ylabel, :title, :xlims, :ylims) + for k in (:xguide, :yguide, :title, :xlims, :ylims) if haskey(d, k) Winston.setattr(wplt, string(get(_winstonNames, k, k)), d[k]) end diff --git a/src/components.jl b/src/components.jl index 146e0eb2..a4adf002 100644 --- a/src/components.jl +++ b/src/components.jl @@ -333,9 +333,9 @@ function update!(a::Axis, args...; kw...) # then override for any keywords... only those keywords that already exists in d for (k,v) in kw - sym = symbol(string(k)[2:end]) - if haskey(d, sym) - d[sym] = v + # sym = symbol(string(k)[2:end]) + if haskey(d, k) + d[k] = v end end a diff --git a/src/old_subplot.jl b/src/old_subplot.jl index 64846daa..3d6a485c 100644 --- a/src/old_subplot.jl +++ b/src/old_subplot.jl @@ -286,8 +286,8 @@ function _add_series_subplot(subplt::Subplot, d::KW, ::Void, args...; # cleanup the dictionary that we pass into the plot! command di[:show] = false di[:subplot] = true - for k in (:title, :xlabel, :xticks, :xlims, :xscale, :xflip, - :ylabel, :yticks, :ylims, :yscale, :yflip) + for k in (:title, :xguide, :xticks, :xlims, :xscale, :xflip, + :yguide, :yticks, :ylims, :yscale, :yflip) delete!(di, k) end dumpdict(di, "subplot! kwList $i") diff --git a/src/plot.jl b/src/plot.jl index 87bde9c5..06ebecc8 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -46,19 +46,25 @@ function plot(args...; kw...) pkg = backend() d = KW(kw) preprocessArgs!(d) + DD(d,"pre") # create an empty Plot, update the args using the inputs, then pass it # to the backend to finish backend-specific initialization plt = Plot() _update_plot_args(plt, d) + DD(plt.plotargs,"pargs") plt.o = _create_backend_figure(plt) # create the layout and subplots from the inputs plt.layout, plt.subplots, plt.spmap = build_layout(plt.plotargs) - for sp in plt.subplots + for (idx,sp) in enumerate(plt.subplots) # update the subplot/axis args from inputs, then pass to backend to init further sp.plt = plt - _update_subplot_args(plt, sp, d) + _update_subplot_args(plt, sp, copy(d), idx) + DD(sp.subplotargs[:xaxis].d,"$idx") + + # TODO: i'd like to know what projection we're using by this point... can I push this off until later?? + # I won't easily be able to auto-determine what series types are coming... _initialize_subplot(plt, sp) end @@ -155,7 +161,8 @@ function _apply_series_recipe(plt::Plot, d::KW) # getting ready to add the series... last update to subplot from anything # that might have been added during series recipes sp = d[:subplot] - _update_subplot_args(plt, sp, d) + sp_idx = get_subplot_index(plt, sp) + _update_subplot_args(plt, sp, d, sp_idx) # adjust extrema and discrete info for s in (:x, :y, :z) @@ -202,8 +209,8 @@ function _plot!(plt::Plot, d::KW, args...) _before_add_series(plt) # first apply any args for the subplots - for sp in plt.subplots - _update_subplot_args(plt, sp, d) + for (idx,sp) in enumerate(plt.subplots) + _update_subplot_args(plt, sp, d, idx) end # the grouping mechanism is a recipe on a GroupBy object @@ -317,6 +324,7 @@ function _plot!(plt::Plot, d::KW, args...) # this is it folks! # 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) + # DD(kw, "series $i before") if !(get(kw, :seriestype, :none) in (:xerror, :yerror)) plt.n += 1 end @@ -327,12 +335,17 @@ function _plot!(plt::Plot, d::KW, args...) sp = 1 # TODO: something useful end sp = kw[:subplot] = get_subplot(plt, sp) + idx = get_subplot_index(plt, sp) # we update subplot args in case something like the color palatte is part of the recipe - _update_subplot_args(plt, sp, kw) + # DD(sp.subplotargs[:xaxis].d, "before USA $i") + # DD(kw, "kw") + _update_subplot_args(plt, sp, kw, idx) + # DD(sp.subplotargs[:xaxis].d, "after USA $i") # set default values, select from attribute cycles, and generally set the final attributes _add_defaults!(kw, plt, sp, i) + # DD(kw, "series $i after") # @@ -342,7 +355,9 @@ function _plot!(plt::Plot, d::KW, args...) # For example, a histogram is just a bar plot with binned data, a bar plot is really a filled step plot, # and a step plot is really just a path. So any backend that supports drawing a path will implicitly # be able to support step, bar, and histogram plots (and any recipes that use those components). + # DD(sp.subplotargs[:xaxis].d, "before $i") _apply_series_recipe(plt, kw) + # DD(sp.subplotargs[:xaxis].d, "after $i") end # now that we're done adding all the series, add the annotations @@ -501,7 +516,7 @@ end # TODO: remove # # should we update the x/y label given the meta info during input slicing? # function updateDictWithMeta(d::KW, plotargs::KW, meta::Symbol, isx::Bool) -# lsym = isx ? :xlabel : :ylabel +# lsym = isx ? :xguide : :yguide # if plotargs[lsym] == default(lsym) # d[lsym] = string(meta) # end diff --git a/src/series_new.jl b/src/series_new.jl index ef3723a0..d17df4a5 100644 --- a/src/series_new.jl +++ b/src/series_new.jl @@ -13,12 +13,14 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int) # for k in keys(_series_defaults) # setDictValue(d, d, k, commandIndex, _series_defaults) # end + + # add default values to our dictionary, being careful not to delete what we just added! for (k,v) in _series_defaults - slice_arg!(d, d, k, v, commandIndex) + slice_arg!(d, d, k, v, commandIndex, remove_pair = false) end # this is how many series belong to this subplot - plotIndex = count(series -> series.d[:subplot] === sp, plt.series_list) + plotIndex = count(series -> series.d[:subplot] === sp, plt.series_list) + 1 # aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex) aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex) diff --git a/src/subplots.jl b/src/subplots.jl index 8aa9785a..30430ec1 100644 --- a/src/subplots.jl +++ b/src/subplots.jl @@ -3,6 +3,8 @@ # ---------------------------------------------------------------------- +Base.show(io::IO, layout::AbstractLayout) = print(io, "$(typeof(layout))$(size(layout))") + # this is the available area for drawing everything in this layout... as percentages of total canvas bbox(layout::AbstractLayout) = layout.bbox bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb) @@ -235,17 +237,62 @@ end # ---------------------------------------------------------------------- -# return the top-level layout, a list of subplots, and a SubplotMap +# # build_layout should return a tuple: (a top-level layout, a list of subplots, and a SubplotMap) +# function build_layout(d::KW) +# layout = get(d, :layout, default(:layout)) +# T = typeof(layout) +# if T <: AbstractLayout +# build_layout(layout) +# elseif T <: Integer +# if layout == 1 +# # just a single subplot +# sp = Subplot(backend()) +# sp, Subplot[sp], SubplotMap((1,1) => sp) +# else +# nr, nc = compute_gridsize(layout) +# build_layout(GridLayout(nr, nc), layout) +# end +# elseif T <: NTuple{2} +# build_layout(GridLayout(layout...)) +# elseif T <: NTuple{3} +# n, nr, nc = layout +# build_layout(GridLayout()) +# else +# error("unhandled layout type $T: $layout") +# end +# end + + +# pass the layout arg through 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) + build_layout(get(d, :layout, default(:layout))) +end - l == :auto || error() # TODO: handle anything else +function build_layout(n::Integer) + nr, nc = compute_gridsize(n, -1, -1) + build_layout(GridLayout(nr, nc), n) +end +function build_layout{I<:Integer}(sztup::NTuple{2,I}) + nr, nc = sztup + build_layout(GridLayout(nr, nc)) +end + +function build_layout{I<:Integer}(sztup::NTuple{3,I}) + n, nr, nc = sztup nr, nc = compute_gridsize(n, nr, nc) - layout = GridLayout(nr, nc) + build_layout(GridLayout(nr, nc), n) +end + +# compute number of subplots +function build_layout(layout::GridLayout) + nr, nc = size(layout) + build_layout(layout, nr*nc) +end + +# n is the number of subplots +function build_layout(layout::GridLayout, n::Integer) + nr, nc = size(layout) subplots = Subplot[] spmap = SubplotMap() i = 1 @@ -260,12 +307,14 @@ function build_layout(d::KW) layout, subplots, spmap end +build_layout(huh) = error("unhandled layout type $(typeof(huh)): $huh") +# ---------------------------------------------------------------------- function compute_gridsize(numplts::Int, nr::Int, nc::Int) # figure out how many rows/columns we need - if nr == -1 - if nc == -1 + if nr < 1 + if nc < 1 nr = round(Int, sqrt(numplts)) nc = ceil(Int, numplts / nr) else @@ -284,6 +333,9 @@ get_subplot(plt::Plot, i::Integer) = plt.subplots[i] get_subplot(plt::Plot, k) = plt.spmap[k] get_subplot(series::Series) = series.d[:subplot] +get_subplot_index(plt::Plot, idx::Integer) = idx +get_subplot_index(plt::Plot, sp::Subplot) = findfirst(sp->sp === plt.subplots[2], plt.subplots) + # ---------------------------------------------------------------------- # ---------------------------------------------------------------------- diff --git a/src/utils.jl b/src/utils.jl index 17075ef9..a4453cf0 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -440,6 +440,7 @@ function dumpdict(d::KW, prefix = "", alwaysshow = false) end println() end +DD(d::KW, prefix = "") = dumpdict(d, prefix, true) function dumpcallstack()