working on arg overhaul

This commit is contained in:
Thomas Breloff 2016-05-17 00:57:42 -04:00
parent b75db9e473
commit 3084b0c41c
11 changed files with 456 additions and 328 deletions

View File

@ -116,7 +116,7 @@ const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
const _series_defaults = KW() const _series_defaults = KW()
# series-specific # series-specific
_series_defaults[:axis] = :left # _series_defaults[:axis] = :left
_series_defaults[:label] = "AUTO" _series_defaults[:label] = "AUTO"
_series_defaults[:seriescolor] = :auto _series_defaults[:seriescolor] = :auto
_series_defaults[:seriesalpha] = nothing _series_defaults[:seriesalpha] = nothing
@ -162,8 +162,7 @@ _series_defaults[:subplot] = :auto # which subplot(s) does this se
const _plot_defaults = KW() const _plot_defaults = KW()
_plot_defaults[:title] = "" _plot_defaults[:title] = ""
_plot_defaults[:legend] = :best _plot_defaults[:titlefont] = font(14)
_plot_defaults[:colorbar] = :legend
_plot_defaults[:background_color] = colorant"white" # default for all backgrounds _plot_defaults[:background_color] = colorant"white" # default for all backgrounds
_plot_defaults[:background_color_outside] = :match # background outside grid _plot_defaults[:background_color_outside] = :match # background outside grid
_plot_defaults[:foreground_color] = :auto # default for all foregrounds, and title color _plot_defaults[:foreground_color] = :auto # default for all foregrounds, and title color
@ -175,7 +174,6 @@ _plot_defaults[:layout] = :auto
_plot_defaults[:num_subplots] = -1 _plot_defaults[:num_subplots] = -1
_plot_defaults[:num_rows] = -1 _plot_defaults[:num_rows] = -1
_plot_defaults[:num_cols] = -1 _plot_defaults[:num_cols] = -1
_plot_defaults[:color_palette] = :auto
_plot_defaults[:link] = false _plot_defaults[:link] = false
_plot_defaults[:linkx] = false _plot_defaults[:linkx] = false
_plot_defaults[:linky] = false _plot_defaults[:linky] = false
@ -192,6 +190,9 @@ _subplot_defaults[:background_color_inside] = :match # background in
_subplot_defaults[:foreground_color_subplot] = :match # default for other fg colors... match takes plot default _subplot_defaults[:foreground_color_subplot] = :match # default for other fg colors... match takes plot default
_subplot_defaults[:foreground_color_legend] = :match # foreground of legend _subplot_defaults[:foreground_color_legend] = :match # foreground of legend
_subplot_defaults[:foreground_color_grid] = :match # grid color _subplot_defaults[:foreground_color_grid] = :match # grid color
_subplot_defaults[:color_palette] = :auto
_subplot_defaults[:legend] = :best
_subplot_defaults[:colorbar] = :legend
_subplot_defaults[:legendfont] = font(8) _subplot_defaults[:legendfont] = font(8)
_subplot_defaults[:grid] = true _subplot_defaults[:grid] = true
_subplot_defaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation) _subplot_defaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
@ -426,41 +427,41 @@ function handleColors!(d::KW, arg, csym::Symbol)
false false
end end
# given one value (:log, or :flip, or (-1,1), etc), set the appropriate arg # # given one value (:log, or :flip, or (-1,1), etc), set the appropriate arg
# TODO: use trueOrAllTrue for subplots which can pass vectors for these # # TODO: use trueOrAllTrue for subplots which can pass vectors for these
function processAxisArg(d::KW, letter::AbstractString, arg) # function processAxisArg(d::KW, letter::AbstractString, arg)
T = typeof(arg) # T = typeof(arg)
arg = get(_scaleAliases, arg, arg) # arg = get(_scaleAliases, arg, arg)
scale, flip, label, lim, tick = axis_symbols(letter, "scale", "flip", "label", "lims", "ticks") # scale, flip, label, lim, tick = axis_symbols(letter, "scale", "flip", "label", "lims", "ticks")
#
if typeof(arg) <: Font # if typeof(arg) <: Font
d[:tickfont] = arg # d[:tickfont] = arg
#
elseif arg in _allScales # elseif arg in _allScales
d[scale] = arg # d[scale] = arg
#
elseif arg in (:flip, :invert, :inverted) # elseif arg in (:flip, :invert, :inverted)
d[flip] = true # d[flip] = true
#
elseif T <: @compat(AbstractString) # elseif T <: @compat(AbstractString)
d[label] = arg # d[label] = arg
#
# xlims/ylims # # xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2 # elseif (T <: Tuple || T <: AVec) && length(arg) == 2
d[typeof(arg[1]) <: Number ? lim : tick] = arg # d[typeof(arg[1]) <: Number ? lim : tick] = arg
#
# xticks/yticks # # xticks/yticks
elseif T <: AVec # elseif T <: AVec
d[tick] = arg # d[tick] = arg
#
elseif arg == nothing # elseif arg == nothing
d[tick] = [] # d[tick] = []
#
else # else
warn("Skipped $(letter)axis arg $arg") # warn("Skipped $(letter)axis arg $arg")
#
end # end
end # end
function processLineArg(d::KW, arg) function processLineArg(d::KW, arg)
@ -575,26 +576,26 @@ end
function preprocessArgs!(d::KW) function preprocessArgs!(d::KW)
replaceAliases!(d, _keyAliases) replaceAliases!(d, _keyAliases)
# handle axis args # # handle axis args
for letter in ("x", "y", "z") # for letter in ("x", "y", "z")
asym = symbol(letter * "axis") # asym = symbol(letter * "axis")
for arg in wraptuple(pop!(d, asym, ())) # for arg in wraptuple(pop!(d, asym, ()))
processAxisArg(d, letter, arg) # processAxisArg(d, letter, arg)
end
# delete!(d, asym)
# # NOTE: this logic was moved to _add_plotargs...
# # turn :labels into :ticks_and_labels
# tsym = symbol(letter * "ticks")
# if haskey(d, tsym) && ticksType(d[tsym]) == :labels
# d[tsym] = (1:length(d[tsym]), d[tsym])
# end # end
# # delete!(d, asym)
# #
# ssym = symbol(letter * "scale") # # # NOTE: this logic was moved to _add_plotargs...
# if haskey(d, ssym) && haskey(_scaleAliases, d[ssym]) # # # turn :labels into :ticks_and_labels
# d[ssym] = _scaleAliases[d[ssym]] # # tsym = symbol(letter * "ticks")
# # if haskey(d, tsym) && ticksType(d[tsym]) == :labels
# # d[tsym] = (1:length(d[tsym]), d[tsym])
# # end
# #
# # ssym = symbol(letter * "scale")
# # if haskey(d, ssym) && haskey(_scaleAliases, d[ssym])
# # d[ssym] = _scaleAliases[d[ssym]]
# # end
# end # end
end
# handle line args # handle line args
for arg in wraptuple(pop!(d, :line, ())) for arg in wraptuple(pop!(d, :line, ()))
@ -668,18 +669,18 @@ function preprocessArgs!(d::KW)
delete!(d, :link) delete!(d, :link)
end end
# pull out invalid keywords into their own KW dict... these are likely user-defined through recipes # # pull out invalid keywords into their own KW dict... these are likely user-defined through recipes
kw = KW() # kw = KW()
for k in keys(d) # for k in keys(d)
try # try
# this should error for invalid keywords (assume they are user-defined) # # this should error for invalid keywords (assume they are user-defined)
k == :markershape_to_add || default(k) # k == :markershape_to_add || default(k)
catch # catch
# not a valid key... pop and add to user list # # not a valid key... pop and add to user list
kw[k] = pop!(d, k) # kw[k] = pop!(d, k)
end # end
end # end
kw # kw
end end
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -744,8 +745,8 @@ _markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supportedM
_markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes]) _markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
function warnOnUnsupported(pkg::AbstractBackend, d::KW) function warnOnUnsupported(pkg::AbstractBackend, d::KW)
(d[:axis] in supportedAxes(pkg) # (d[:axis] in supportedAxes(pkg)
|| warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))")) # || warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
(d[:seriestype] == :none (d[:seriestype] == :none
|| d[:seriestype] in supportedTypes(pkg) || d[:seriestype] in supportedTypes(pkg)
|| warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supportedTypes(pkg))")) || warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supportedTypes(pkg))"))
@ -767,28 +768,16 @@ end
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 1-row matrices will give an element
# multi-row matrices will give a column
# InputWrapper just gives the contents
# anything else is returned as-is
# getArgValue(v::Tuple, idx::Int) = v[mod1(idx, length(v))]
function getArgValue(v::AMat, idx::Int)
c = mod1(idx, size(v,2))
size(v,1) == 1 ? v[1,c] : v[:,c]
end
getArgValue(wrapper::InputWrapper, idx) = wrapper.obj
getArgValue(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. # # if nothing is set (rarg is empty), return the default.
# if nothing is set (or container is empty), return the default. # function setDictValue(d_in::KW, d_out::KW, k::Symbol, idx::Int, defaults::KW)
function setDictValue(d_in::KW, d_out::KW, k::Symbol, idx::Int, defaults::KW) # if haskey(d_in, k) && !(typeof(d_in[k]) <: Union{AbstractMatrix, Tuple} && isempty(d_in[k]))
if haskey(d_in, k) && !(typeof(d_in[k]) <: Union{AbstractMatrix, Tuple} && isempty(d_in[k])) # d_out[k] = slice_arg(d_in[k], idx)
d_out[k] = getArgValue(d_in[k], idx) # else
else # d_out[k] = deepcopy(defaults[k])
d_out[k] = deepcopy(defaults[k]) # end
end # end
end
function convertLegendValue(val::Symbol) function convertLegendValue(val::Symbol)
if val in (:both, :all, :yes) if val in (:both, :all, :yes)
@ -806,39 +795,139 @@ convertLegendValue(val::Bool) = val ? :best : :none
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# build the argument dictionary for the plot # build the argument dictionary for the plot
function getPlotArgs(pkg::AbstractBackend, kw, idx::Int; set_defaults = true) # function getPlotArgs(pkg::AbstractBackend, kw, idx::Int; set_defaults = true)
kwdict = KW(kw) # d_in = KW(kw)
d = KW() # d_out = KW()
# add defaults?
if set_defaults
for k in keys(_plot_defaults)
setDictValue(kwdict, d, k, idx, _plot_defaults)
end
end
# #
# for k in (:xscale, :yscale) # # add defaults?
# if haskey(_scaleAliases, d[k]) # if set_defaults
# d[k] = _scaleAliases[d[k]] # for k in keys(_plot_defaults)
# setDictValue(d_in, d_out, k, idx, _plot_defaults)
# end # end
# end # end
#
# # handle legend/colorbar
# d_out[:legend] = convertLegendValue(d_out[:legend])
# d_out[:colorbar] = convertLegendValue(d_out[:colorbar])
# if d_out[:colorbar] == :legend
# d_out[:colorbar] = d_out[:legend]
# end
#
# # convert color
# handlePlotColors(pkg, d_out)
#
# # no need for these
# delete!(d_out, :x)
# delete!(d_out, :y)
#
# d_out
# end
# 1-row matrices will give an element
# multi-row matrices will give a column
# InputWrapper just gives the contents
# anything else is returned as-is
function slice_arg(v::AMat, idx::Int)
c = mod1(idx, size(v,2))
size(v,1) == 1 ? v[1,c] : v[:,c]
end
slice_arg(wrapper::InputWrapper, idx) = wrapper.obj
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)
slice_arg(v, idx)
else
v
end
end
# if the value is `:match` then we take whatever match_color is.
# this is mainly used for cascading defaults for foreground and background colors
function color_or_match!(d::KW, k::Symbol, match_color)
v = d[k]
d[k] = if v == :match
match_color
elseif v == nothing
colorscheme(RGBA(0,0,0,0))
else
v
end
end
# update plotargs from an input dictionary
function _update_plot_args(plt::Plot, d_in::KW)
pargs = plt.plotargs
for (k,v) in _plot_defaults
slice_arg!(d_in, pargs, k, v)
end
# handle colors
bg = convertColor(pargs[:background_color])
fg = pargs[:foreground_color]
if fg == :auto
fg = isdark(bg) ? colorant"white" : colorant"black"
end
pargs[:background_color] = bg
pargs[:foreground_color] = convertColor(fg)
color_or_match!(pargs, :background_color_outside, bg)
end
# update a subplots args and axes
function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW)
pargs = plt.plotargs
spargs = sp.subplotargs
for (k,v) in _subplot_defaults
slice_arg!(d_in, spargs, k, v)
end
# handle legend/colorbar # handle legend/colorbar
d[:legend] = convertLegendValue(d[:legend]) spargs[:legend] = convertLegendValue(spargs[:legend])
d[:colorbar] = convertLegendValue(d[:colorbar]) spargs[:colorbar] = convertLegendValue(spargs[:colorbar])
if d[:colorbar] == :legend if spargs[:colorbar] == :legend
d[:colorbar] = d[:legend] spargs[:colorbar] = spargs[:legend]
end end
# convert color # background colors
handlePlotColors(pkg, d) bg = color_or_match!(spargs, :background_color_subplot, pargs[:background_color])
spargs[:color_palette] = get_color_palette(spargs[:color_palette], bg, 30)
color_or_match!(spargs, :background_color_legend, bg)
color_or_match!(spargs, :background_color_inside, bg)
# no need for these # foreground colors
delete!(d, :x) fg = color_or_match!(spargs, :foreground_color_subplot, pargs[:foreground_color])
delete!(d, :y) color_or_match!(spargs, :foreground_color_legend, fg)
color_or_match!(spargs, :foreground_color_grid, fg)
d for letter in (:x, :y, :z)
# get (maybe initialize) the axis
axissym = symbol(letter, :axis)
axis = get!(spargs, axissym, Axis(letter))
# grab magic args (for example `xaxis = (:flip, :log)`)
args = wraptuple(get(d_in, axissym, ()))
# build the KW of arguments from the letter version (i.e. xticks --> ticks)
kw = KW()
for k in _axis_defaults
lk = symbol(letter, k)
if haskey(d_in, lk)
kw[k] = d_in[lk]
end end
end
# update the axis
update!(axis, args...; kw...)
end
end
function has_black_border_for_default(st::Symbol) function has_black_border_for_default(st::Symbol)
like_histogram(st) || st in (:hexbin, :bar) like_histogram(st) || st in (:hexbin, :bar)

View File

@ -22,7 +22,7 @@ supportedArgs(::GRBackend) = [
:title, :windowtitle, :show, :size, :title, :windowtitle, :show, :size,
:x, :xlabel, :xlims, :xticks, :xscale, :xflip, :x, :xlabel, :xlims, :xticks, :xscale, :xflip,
:y, :ylabel, :ylims, :yticks, :yscale, :yflip, :y, :ylabel, :ylims, :yticks, :yscale, :yflip,
:axis, :yrightlabel, # :axis, :yrightlabel,
:z, :zlabel, :zlims, :zticks, :zscale, :zflip, :z, :zlabel, :zlims, :zticks, :zscale, :zflip,
:z, :z,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
@ -80,7 +80,8 @@ function gr_getcolorind(v)
end end
function gr_getaxisind(p) function gr_getaxisind(p)
axis = get(p, :axis, :none) # axis = get(p, :axis, :none)
axis = :left
if axis in [:none, :left] if axis in [:none, :left]
return 1 return 1
else else
@ -423,14 +424,14 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
GR.text(vp[1], 0.5 * (viewport[3] + viewport[4]), d[:ylabel]) GR.text(vp[1], 0.5 * (viewport[3] + viewport[4]), d[:ylabel])
GR.restorestate() GR.restorestate()
end end
if get(d, :yrightlabel, "") != "" # if get(d, :yrightlabel, "") != ""
GR.savestate() # GR.savestate()
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) # GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.setcharup(1, 0) # GR.setcharup(1, 0)
GR.settextcolorind(fg) # GR.settextcolorind(fg)
GR.text(vp[2], 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel]) # GR.text(vp[2], 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel])
GR.restorestate() # GR.restorestate()
end # end
GR.setcolormap(1000 + GR.COLORMAP_COOLWARM) GR.setcolormap(1000 + GR.COLORMAP_COOLWARM)

View File

@ -22,7 +22,7 @@ supportedArgs(::PyPlotBackend) = [
:title, :windowtitle, :show, :size, :title, :windowtitle, :show, :size,
:x, :xlabel, :xlims, :xticks, :xscale, :xflip, :xrotation, :x, :xlabel, :xlims, :xticks, :xscale, :xflip, :xrotation,
:y, :ylabel, :ylims, :yticks, :yscale, :yflip, :yrotation, :y, :ylabel, :ylims, :yticks, :yscale, :yflip, :yrotation,
:axis, :yrightlabel, # :axis, :yrightlabel,
:z, :zlabel, :zlims, :zticks, :zscale, :zflip, :zrotation, :z, :zlabel, :zlims, :zticks, :zscale, :zflip, :zrotation,
:z, :z,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
@ -881,7 +881,7 @@ function _add_series(plt::Plot{PyPlotBackend}, series::Series)
end end
# this sets the bg color inside the grid # this sets the bg color inside the grid
ax[:set_axis_bgcolor](getPyPlotColor(plt.plotargs[:background_color_inside])) ax[:set_axis_bgcolor](getPyPlotColor(d[:subplot].subplotargs[:background_color_inside]))
# handle area filling # handle area filling
fillrange = d[:fillrange] fillrange = d[:fillrange]
@ -1030,21 +1030,20 @@ function applyPyPlotScale(ax, scaleType::Symbol, letter)
end end
function updateAxisColors(ax, d::KW) function updateAxisColors(ax, a::Axis)
guidecolor = getPyPlotColor(d[:foreground_color_guide]) guidecolor = getPyPlotColor(a[:foreground_color_guide])
for (loc, spine) in ax[:spines] for (loc, spine) in ax[:spines]
spine[:set_color](getPyPlotColor(d[:foreground_color_border])) spine[:set_color](getPyPlotColor(a[:foreground_color_border]))
end end
for letter in ("x", "y", "z") # for letter in ("x", "y", "z")
axis = axis_symbol(letter, "axis") axis = axis_symbol(letter, "axis")
if haskey(ax, axis) if haskey(ax, axis)
ax[:tick_params](axis=letter, which="both", ax[:tick_params](axis=letter, which="both",
colors=getPyPlotColor(d[:foreground_color_axis]), colors=getPyPlotColor(a[:foreground_color_axis]),
labelcolor=getPyPlotColor(d[:foreground_color_text])) labelcolor=getPyPlotColor(a[:foreground_color_text]))
ax[axis][:label][:set_color](guidecolor) ax[axis][:label][:set_color](guidecolor)
end end
end # end
ax[:title][:set_color](guidecolor)
end end
# function usingRightAxis(plt::Plot{PyPlotBackend}) # function usingRightAxis(plt::Plot{PyPlotBackend})
@ -1060,13 +1059,14 @@ function _update_plot(plt::Plot{PyPlotBackend}, d::KW)
# figorax = plt.o # figorax = plt.o
# ax = getLeftAxis(figorax) # ax = getLeftAxis(figorax)
for sp in plt.subplots for sp in plt.subplots
spargs = sp.subplotargs
ax = getAxis(sp) ax = getAxis(sp)
# ticksz = get(d, :tickfont, plt.plotargs[:tickfont]).pointsize # ticksz = get(d, :tickfont, plt.plotargs[:tickfont]).pointsize
guidesz = get(d, :guidefont, plt.plotargs[:guidefont]).pointsize # guidesz = get(d, :guidefont, spargs[:guidefont]).pointsize
# title # title
haskey(d, :title) && ax[:set_title](d[:title]) haskey(d, :title) && ax[:set_title](d[:title])
ax[:title][:set_fontsize](guidesz) ax[:title][:set_fontsize](plt.plotargs[:titlefont].pointsize)
# axes = [ax] # axes = [ax]
# # handle right y axis # # handle right y axis
@ -1079,9 +1079,9 @@ function _update_plot(plt::Plot{PyPlotBackend}, d::KW)
# end # end
# end # end
for letter in ("x", "y", "z") for letter in (:x, :y, :z)
axissym = symbol(letter*"axis") axissym = symbol(letter, :axis)
axis = plt.plotargs[axissym] axis = spargs[axissym]
# @show axis # @show axis
haskey(ax, axissym) || continue haskey(ax, axissym) || continue
applyPyPlotScale(ax, axis[:scale], letter) applyPyPlotScale(ax, axis[:scale], letter)
@ -1099,7 +1099,7 @@ function _update_plot(plt::Plot{PyPlotBackend}, d::KW)
lab[:set_rotation](axis[:rotation]) lab[:set_rotation](axis[:rotation])
end end
if get(d, :grid, false) if get(d, :grid, false)
fgcolor = getPyPlotColor(plt.plotargs[:foreground_color_grid]) fgcolor = getPyPlotColor(spargs[:foreground_color_grid])
tmpax[axissym][:grid](true, color = fgcolor) tmpax[axissym][:grid](true, color = fgcolor)
tmpax[:set_axisbelow](true) tmpax[:set_axisbelow](true)
end end
@ -1253,14 +1253,17 @@ const _pyplot_legend_pos = KW(
) )
# function addPyPlotLegend(plt::Plot) # function addPyPlotLegend(plt::Plot)
function addPyPlotLegend(plt::Plot, ax) # function addPyPlotLegend(plt::Plot, ax)
leg = plt.plotargs[:legend] function addPyPlotLegend(plt::Plot, sp::Subplot, ax)
leg = sp.subplotargs[:legend]
if leg != :none if leg != :none
# gotta do this to ensure both axes are included # gotta do this to ensure both axes are included
labels = [] labels = []
handles = [] handles = []
for series in plt.series_list for series in plt.series_list
if series.d[:label] != "" && !(series.d[:seriestype] in ( if get_subplot(series) === sp &&
series.d[:label] != "" &&
!(series.d[:seriestype] in (
:hist,:density,:hexbin,:hist2d,:hline,:vline, :hist,:density,:hexbin,:hist2d,:hline,:vline,
:contour,:contour3d,:surface,:wireframe, :contour,:contour3d,:surface,:wireframe,
:heatmap,:path3d,:scatter3d, :pie, :image)) :heatmap,:path3d,:scatter3d, :pie, :image))
@ -1280,19 +1283,19 @@ function addPyPlotLegend(plt::Plot, ax)
labels, #[d[:label] for d in args], labels, #[d[:label] for d in args],
loc = get(_pyplot_legend_pos, leg, "best"), loc = get(_pyplot_legend_pos, leg, "best"),
scatterpoints = 1, scatterpoints = 1,
fontsize = plt.plotargs[:legendfont].pointsize fontsize = sp.subplotargs[:legendfont].pointsize
# framealpha = 0.6 # framealpha = 0.6
) )
leg[:set_zorder](1000) leg[:set_zorder](1000)
fgcolor = getPyPlotColor(plt.plotargs[:foreground_color_legend]) fgcolor = getPyPlotColor(sp.subplotargs[:foreground_color_legend])
for txt in leg[:get_texts]() for txt in leg[:get_texts]()
PyPlot.plt[:setp](txt, color = fgcolor) PyPlot.plt[:setp](txt, color = fgcolor)
end end
# set some legend properties # set some legend properties
frame = leg[:get_frame]() frame = leg[:get_frame]()
frame[:set_facecolor](getPyPlotColor(plt.plotargs[:background_color_legend])) frame[:set_facecolor](getPyPlotColor(sp.subplotargs[:background_color_legend]))
frame[:set_edgecolor](fgcolor) frame[:set_edgecolor](fgcolor)
end end
end end
@ -1304,8 +1307,11 @@ function finalizePlot(plt::Plot{PyPlotBackend})
for sp in plt.subplots for sp in plt.subplots
# ax = getLeftAxis(plt) # ax = getLeftAxis(plt)
ax = getAxis(sp) ax = getAxis(sp)
addPyPlotLegend(plt, ax) addPyPlotLegend(plt, sp, ax)
updateAxisColors(ax, plt.plotargs) for asym in (:xaxis, :yaxis, :zaxis)
updateAxisColors(ax, sp.subplotargs[asym])
end
ax[:title][:set_color](getPyPlotColor(plt.plotargs[:titlefont].color))
end end
drawfig(plt.o) drawfig(plt.o)
update_bboxes!(plt.layout) update_bboxes!(plt.layout)

View File

@ -173,10 +173,10 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
end end
function handlePlotColors(::UnicodePlotsBackend, d::KW) # function handlePlotColors(::UnicodePlotsBackend, d::KW)
# TODO: something special for unicodeplots, since it doesn't take kindly to people messing with its color palette # # TODO: something special for unicodeplots, since it doesn't take kindly to people messing with its color palette
d[:color_palette] = [RGB(0,0,0)] # d[:color_palette] = [RGB(0,0,0)]
end # end
# ------------------------------- # -------------------------------
@ -189,6 +189,7 @@ function _create_backend_figure(plt::Plot{UnicodePlotsBackend})
if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == default(:size) if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == default(:size)
plt.plotargs[:size] = (60,20) plt.plotargs[:size] = (60,20)
end end
plt.plotargs[:color_palette] = [RGB(0,0,0)]
nothing nothing
# plt # plt

View File

@ -294,7 +294,7 @@ function generate_colorgradient(bgcolor = colorant"white";
gradient_from_list(colors) gradient_from_list(colors)
end end
function get_color_palette(palette, bgcolor::@compat(Union{Colorant,ColorWrapper}), numcolors::Integer) function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
grad = if palette == :auto grad = if palette == :auto
generate_colorgradient(bgcolor) generate_colorgradient(bgcolor)
else else
@ -304,7 +304,8 @@ function get_color_palette(palette, bgcolor::@compat(Union{Colorant,ColorWrapper
RGBA[getColorZ(grad, z) for z in zrng] RGBA[getColorZ(grad, z) for z in zrng]
end end
function get_color_palette(palette::Vector{RGBA}, bgcolor::@compat(Union{Colorant,ColorWrapper}), numcolors::Integer) function get_color_palette{C<:Colorant}(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
palette palette
end end
@ -360,55 +361,55 @@ webcolor(c, α) = webcolor(convertColor(getColor(c), α))
# TODO: allow the setting of the algorithm, either by passing a symbol (:colordiff, :fixed, etc) or a function? # TODO: allow the setting of the algorithm, either by passing a symbol (:colordiff, :fixed, etc) or a function?
function handlePlotColors(::AbstractBackend, d::KW) # function handlePlotColors(::AbstractBackend, d::KW)
if :background_color in supportedArgs() # if :background_color in supportedArgs()
bgcolor = convertColor(d[:background_color]) # bgcolor = convertColor(d[:background_color])
else # else
bgcolor = default(:background_color) # bgcolor = default(:background_color)
if d[:background_color] != default(:background_color) # if d[:background_color] != default(:background_color)
warn("Cannot set background_color with backend $(backend())") # warn("Cannot set background_color with backend $(backend())")
end # end
end # end
#
#
d[:color_palette] = get_color_palette(get(d, :color_palette, :auto), bgcolor, 100) # d[:color_palette] = get_color_palette(get(d, :color_palette, :auto), bgcolor, 100)
#
#
# set the foreground color (text, ticks, gridlines) to be white or black depending # # set the foreground color (text, ticks, gridlines) to be white or black depending
# on how dark the background is. # # on how dark the background is.
fgcolor = get(d, :foreground_color, :auto) # fgcolor = get(d, :foreground_color, :auto)
fgcolor = if fgcolor == :auto # fgcolor = if fgcolor == :auto
isdark(bgcolor) ? colorant"white" : colorant"black" # isdark(bgcolor) ? colorant"white" : colorant"black"
else # else
convertColor(fgcolor) # convertColor(fgcolor)
end # end
#
# bg/fg color # # bg/fg color
d[:background_color] = colorscheme(bgcolor) # d[:background_color] = colorscheme(bgcolor)
d[:foreground_color] = colorscheme(fgcolor) # d[:foreground_color] = colorscheme(fgcolor)
#
# update sub-background colors # # update sub-background colors
for bgtype in ("legend", "inside", "outside") # for bgtype in ("legend", "inside", "outside")
bgsym = symbol("background_color_" * bgtype) # bgsym = symbol("background_color_" * bgtype)
if d[bgsym] == :match # if d[bgsym] == :match
d[bgsym] = d[:background_color] # d[bgsym] = d[:background_color]
elseif d[bgsym] == nothing # elseif d[bgsym] == nothing
d[bgsym] = colorscheme(RGBA(0,0,0,0)) # d[bgsym] = colorscheme(RGBA(0,0,0,0))
end # end
end # end
#
# update sub-foreground colors # # update sub-foreground colors
for fgtype in ("legend", "grid", "axis", "text", "border", "guide") # for fgtype in ("legend", "grid", "axis", "text", "border", "guide")
fgsym = symbol("foreground_color_" * fgtype) # fgsym = symbol("foreground_color_" * fgtype)
if d[fgsym] == :match # if d[fgsym] == :match
d[fgsym] = d[:foreground_color] # d[fgsym] = d[:foreground_color]
elseif d[fgsym] == nothing # elseif d[fgsym] == nothing
d[fgsym] = colorscheme(RGBA(0,0,0,0)) # d[fgsym] = colorscheme(RGBA(0,0,0,0))
end # end
end # end
#
#
end # end
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically # converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, plotargs::KW, n::Int) function getSeriesRGBColor(c, plotargs::KW, n::Int)

View File

@ -258,21 +258,21 @@ end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
xaxis(args...) = Axis("x", args...) xaxis(args...) = Axis(:x, args...)
yaxis(args...) = Axis("y", args...) yaxis(args...) = Axis(:y, args...)
zaxis(args...) = Axis("z", args...) zaxis(args...) = Axis(:z, args...)
const _axis_symbols = (:label, :lims, :ticks, :scale, :flip, :rotation) # const _axis_symbols = (:label, :lims, :ticks, :scale, :flip, :rotation)
const _axis_symbols_fonts_colors = ( # const _axis_symbols_fonts_colors = (
:guidefont, :tickfont, # :guidefont, :tickfont,
:foreground_color_axis, # :foreground_color_axis,
:foreground_color_border, # :foreground_color_border,
:foreground_color_text, # :foreground_color_text,
:foreground_color_guide # :foreground_color_guide
) # )
function Axis(letter::AbstractString, args...; kw...) function Axis(letter::Symbol, args...; kw...)
# init with values from _plot_defaults # init with values from _plot_defaults
d = KW( d = KW(
:letter => letter, :letter => letter,
@ -283,13 +283,6 @@ function Axis(letter::AbstractString, args...; kw...)
:show => true, # show or hide the axis? (useful for linked subplots) :show => true, # show or hide the axis? (useful for linked subplots)
) )
merge!(d, _axis_defaults) 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 the defaults
update!(Axis(d), args...; kw...) update!(Axis(d), args...; kw...)

View File

@ -47,22 +47,18 @@ function plot(args...; kw...)
d = KW(kw) d = KW(kw)
preprocessArgs!(d) preprocessArgs!(d)
# subplots = Subplot[layout] # TODO: build full list # create an empty Plot, update the args using the inputs, then pass it
# smap = SubplotMap(1 => layout) # TODO: actually build a map # to the backend to finish backend-specific initialization
plt = Plot()
# TODO: this seems wrong... I only call getPlotArgs when creating a new plot?? _update_plot_args(plt, d)
plotargs = merge(d, getPlotArgs(pkg, d, 1))
# plt = _create_plot(pkg, plotargs) # create a new, blank plot
# plt = Plot(nothing, pkg, 0, plotargs, Series[]) #, subplots, spmap, layout)
plt = Plot(plotargs)
plt.o = _create_backend_figure(plt) plt.o = _create_backend_figure(plt)
plt.layout, plt.subplots, plt.spmap = build_layout(pop!(d, :layout, :auto)) # create the layout and subplots from the inputs
plt.layout, plt.subplots, plt.spmap = build_layout(plt.plotargs)
for sp in plt.subplots for sp in plt.subplots
@show sp.o # update the subplot/axis args from inputs, then pass to backend to init further
_update_subplot_args(plt, sp, d)
_initialize_subplot(plt, sp) _initialize_subplot(plt, sp)
@show sp.o
end end
# now update the plot # now update the plot
@ -94,58 +90,58 @@ function strip_first_letter(s::Symbol)
str[1:1], symbol(str[2:end]) str[1:1], symbol(str[2:end])
end end
# TODO: need to apply axis args to the axes, subplot args to the subplots, and plot args to the plot # # 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 # # merge the KW d into the plot args
function _add_plotargs!(plt::Plot, d::KW) # function _add_plotargs!(plt::Plot, d::KW)
# @show d # # @show d
#
# handle axis updates from a recipe # # handle axis updates from a recipe
for letter in ("x","y","z") # for letter in ("x","y","z")
# get the Axis object # # get the Axis object
asym = symbol(letter * "axis") # asym = symbol(letter * "axis")
axis = plt.plotargs[asym] # axis = plt.plotargs[asym]
if axis == nothing # if axis == nothing
# create a new one on first pass # # create a new one on first pass
axis = Axis(letter) # axis = Axis(letter)
end # end
# @show 1,typeof(axis) # # @show 1,typeof(axis)
#
# update xlabel, xscale, etc # # update xlabel, xscale, etc
for k in _axis_symbols # for k in _axis_symbols
lk = symbol(letter * string(k)) # lk = symbol(letter * string(k))
if haskey(d, lk) # if haskey(d, lk)
axis[k] = d[lk] # axis[k] = d[lk]
end # end
end # end
# @show 2,axis # # @show 2,axis
#
# update guidefont, etc # # update guidefont, etc
for k in _axis_symbols_fonts_colors # for k in _axis_symbols_fonts_colors
if haskey(d, k) # if haskey(d, k)
axis[k] = d[k] # axis[k] = d[k]
end # end
end # end
# @show 3,axis # # @show 3,axis
#
# update extrema and discrete values # # update extrema and discrete values
datasym = symbol(letter) # datasym = symbol(letter)
if haskey(d, datasym) # if haskey(d, datasym)
v = d[datasym] # v = d[datasym]
if eltype(v) <: Number # if eltype(v) <: Number
expand_extrema!(axis, v) # expand_extrema!(axis, v)
else # else
d[datasym] = discrete_value!(axis, v) # d[datasym] = discrete_value!(axis, v)
end # end
end # end
# @show 4,axis # # @show 4,axis
end # end
#
for k in keys(_plot_defaults) # for k in keys(_plot_defaults)
if haskey(d, k) # if haskey(d, k)
plt.plotargs[k] = pop!(d, k) # plt.plotargs[k] = pop!(d, k)
end # end
end # end
end # end
# this method recursively applies series recipes when the seriestype is not supported # this method recursively applies series recipes when the seriestype is not supported
# natively by the backend # natively by the backend
@ -154,11 +150,32 @@ function _apply_series_recipe(plt::Plot, d::KW)
# dumpdict(d, "apply_series_recipe", true) # dumpdict(d, "apply_series_recipe", true)
if st in supportedTypes() if st in supportedTypes()
# println("adding series!!") # println("adding series!!")
# 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)
# adjust extrema and discrete info
for s in (:x, :y, :z)
data = d[s]
axis = sp.subplotargs[symbol(s, "axis")]
if eltype(data) <: Number
expand_extrema!(axis, data)
else
# TODO: need more here... gotta track the discrete reference value
# as well as any coord offset (think of boxplot shape coords... they all
# correspond to the same x-value)
d[s] = discrete_value!(axis, data)
end
end
# add the series!
warnOnUnsupported(plt.backend, d) warnOnUnsupported(plt.backend, d)
series = Series(d) series = Series(d)
push!(plt.series_list, series) push!(plt.series_list, series)
# _add_series(plt.backend, plt, d)
_add_series(plt, series) _add_series(plt, series)
else else
# get a sub list of series for this seriestype # get a sub list of series for this seriestype
series_list = try series_list = try
@ -275,15 +292,17 @@ function _plot!(plt::Plot, d::KW, args...)
# @show typeof((kw[:x], kw[:y], kw[:z])) # @show typeof((kw[:x], kw[:y], kw[:z]))
# end # end
# merge plot args... this is where we combine all the plot args from the user and # # merge plot args... this is where we combine all the plot args from the user and
# from the recipes... axis info, colors, etc # # from the recipes... axis info, colors, etc
# TODO: why do i need to check for the subplot key? # # TODO: why do i need to check for the subplot key?
# if !haskey(d, :subplot) # # if !haskey(d, :subplot)
for kw in vcat(kw_list, d) # # for kw in vcat(kw_list, d)
_add_plotargs!(plt, kw) # for kw in kw_list
end # _update_subplot_args(plt, kw[:subplot], kw)
handlePlotColors(plt.backend, plt.plotargs) # # _add_plotargs!(plt, kw)
# end # end
# # handlePlotColors(plt.backend, plt.plotargs)
# # end
# for kw in kw_list # for kw in kw_list
# @show typeof((kw[:x], kw[:y], kw[:z])) # @show typeof((kw[:x], kw[:y], kw[:z]))
@ -296,10 +315,20 @@ function _plot!(plt::Plot, d::KW, args...)
plt.n += 1 plt.n += 1
end end
# set default values, select from attribute cycles, and generally set the final attributes # get the Subplot object to which the series belongs
_add_defaults!(kw, plt, i) sp = slice_arg(kw[:subplot], i)
if sp == :auto
sp = 1 # TODO: something useful
end
sp = kw[:subplot] = get_subplot(plt, sp)
_replace_linewidth(kw) # we update subplot args in case something like the color palatte is part of the recipe
_update_subplot_args(plt, sp, kw)
# set default values, select from attribute cycles, and generally set the final attributes
_add_defaults!(kw, plt, sp, i)
#
# now we have a fully specified series, with colors chosen. we must recursively handle # now we have a fully specified series, with colors chosen. we must recursively handle
# series recipes, which dispatch on seriestype. If a backend does not natively support a seriestype, # series recipes, which dispatch on seriestype. If a backend does not natively support a seriestype,

View File

@ -2,29 +2,30 @@
# we are going to build recipes to do the processing and splitting of the args # we are going to build recipes to do the processing and splitting of the args
function _add_defaults!(d::KW, plt::Plot, commandIndex::Int) function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
pkg = plt.backend pkg = plt.backend
n = plt.n # n = plt.n
plotargs = getplotargs(plt, n) # plotargs = getplotargs(plt, n)
plotIndex = convertSeriesIndex(plt, n) # plotIndex = convertSeriesIndex(plt, n)
globalIndex = n globalIndex = plt.n
# add defaults? # # add defaults?
for k in keys(_series_defaults) # for k in keys(_series_defaults)
setDictValue(d, d, k, commandIndex, _series_defaults) # setDictValue(d, d, k, commandIndex, _series_defaults)
# end
for (k,v) in _series_defaults
slice_arg!(d, d, k, v, commandIndex)
end end
if d[:subplot] == :auto # this is how many series belong to this subplot
# TODO: something useful plotIndex = count(series -> series.d[:subplot] === sp, plt.series_list)
d[:subplot] = 1
end
aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex) # aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex)
aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex) aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex) aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
# update color # update color
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], plotargs, plotIndex) d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], sp.subplotargs, plotIndex)
# update colors # update colors
for csym in (:linecolor, :markercolor, :fillcolor) for csym in (:linecolor, :markercolor, :fillcolor)
@ -35,13 +36,17 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
d[:seriescolor] d[:seriescolor]
end end
else else
getSeriesRGBColor(d[csym], plotargs, plotIndex) getSeriesRGBColor(d[csym], sp.subplotargs, plotIndex)
end end
end end
# update markerstrokecolor # update markerstrokecolor
c = d[:markerstrokecolor] c = d[:markerstrokecolor]
c = (c == :match ? plotargs[:foreground_color] : getSeriesRGBColor(c, plotargs, plotIndex)) c = if c == :match
sp.subplotargs[:foreground_color_subplot]
else
getSeriesRGBColor(c, sp.subplotargs, plotIndex)
end
d[:markerstrokecolor] = c d[:markerstrokecolor] = c
# update alphas # update alphas
@ -62,11 +67,12 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
# set label # set label
label = d[:label] label = d[:label]
label = (label == "AUTO" ? "y$globalIndex" : label) label = (label == "AUTO" ? "y$globalIndex" : label)
if d[:axis] == :right && !(length(label) >= 4 && label[end-3:end] != " (R)") # if d[:axis] == :right && !(length(label) >= 4 && label[end-3:end] != " (R)")
label = string(label, " (R)") # label = string(label, " (R)")
end # end
d[:label] = label d[:label] = label
_replace_linewidth(d)
d d
end end

View File

@ -223,6 +223,7 @@ end
get_subplot(plt::Plot, sp::Subplot) = sp get_subplot(plt::Plot, sp::Subplot) = sp
get_subplot(plt::Plot, i::Integer) = plt.subplots[i] get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
get_subplot(plt::Plot, k) = plt.spmap[k] get_subplot(plt::Plot, k) = plt.spmap[k]
get_subplot(series::Series) = series.d[:subplot]
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------

View File

@ -133,8 +133,9 @@ type Plot{T<:AbstractBackend} <: AbstractPlot{T}
layout::AbstractLayout layout::AbstractLayout
end end
function Plot(plotargs::KW) function Plot()
Plot(backend(), 0, plotargs, Series[], nothing, Subplot[], SubplotMap(), EmptyLayout()) Plot(backend(), 0, KW(), Series[], nothing,
Subplot[], SubplotMap(), EmptyLayout())
end end
# ----------------------------------------------------------- # -----------------------------------------------------------

View File

@ -268,8 +268,8 @@ limsType{T<:Real,S<:Real}(lims::@compat(Tuple{T,S})) = :limits
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid limsType(lims) = :invalid
axis_symbol(letter, postfix) = symbol(letter * postfix) # axis_symbol(letter, postfix) = symbol(letter * postfix)
axis_symbols(letter, postfix...) = map(s -> axis_symbol(letter, s), postfix) # axis_symbols(letter, postfix...) = map(s -> axis_symbol(letter, s), postfix)
Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng] Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng]
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng] Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng]