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()
# series-specific
_series_defaults[:axis] = :left
# _series_defaults[:axis] = :left
_series_defaults[:label] = "AUTO"
_series_defaults[:seriescolor] = :auto
_series_defaults[:seriesalpha] = nothing
@ -162,8 +162,7 @@ _series_defaults[:subplot] = :auto # which subplot(s) does this se
const _plot_defaults = KW()
_plot_defaults[:title] = ""
_plot_defaults[:legend] = :best
_plot_defaults[:colorbar] = :legend
_plot_defaults[:titlefont] = font(14)
_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, and title color
@ -175,7 +174,6 @@ _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
@ -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_legend] = :match # foreground of legend
_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[:grid] = true
_subplot_defaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
@ -426,41 +427,41 @@ function handleColors!(d::KW, arg, csym::Symbol)
false
end
# 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
function processAxisArg(d::KW, letter::AbstractString, arg)
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
scale, flip, label, lim, tick = axis_symbols(letter, "scale", "flip", "label", "lims", "ticks")
if typeof(arg) <: Font
d[:tickfont] = arg
elseif arg in _allScales
d[scale] = arg
elseif arg in (:flip, :invert, :inverted)
d[flip] = true
elseif T <: @compat(AbstractString)
d[label] = arg
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
d[typeof(arg[1]) <: Number ? lim : tick] = arg
# xticks/yticks
elseif T <: AVec
d[tick] = arg
elseif arg == nothing
d[tick] = []
else
warn("Skipped $(letter)axis arg $arg")
end
end
# # 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
# function processAxisArg(d::KW, letter::AbstractString, arg)
# T = typeof(arg)
# arg = get(_scaleAliases, arg, arg)
# scale, flip, label, lim, tick = axis_symbols(letter, "scale", "flip", "label", "lims", "ticks")
#
# if typeof(arg) <: Font
# d[:tickfont] = arg
#
# elseif arg in _allScales
# d[scale] = arg
#
# elseif arg in (:flip, :invert, :inverted)
# d[flip] = true
#
# elseif T <: @compat(AbstractString)
# d[label] = arg
#
# # xlims/ylims
# elseif (T <: Tuple || T <: AVec) && length(arg) == 2
# d[typeof(arg[1]) <: Number ? lim : tick] = arg
#
# # xticks/yticks
# elseif T <: AVec
# d[tick] = arg
#
# elseif arg == nothing
# d[tick] = []
#
# else
# warn("Skipped $(letter)axis arg $arg")
#
# end
# end
function processLineArg(d::KW, arg)
@ -575,26 +576,26 @@ end
function preprocessArgs!(d::KW)
replaceAliases!(d, _keyAliases)
# handle axis args
for letter in ("x", "y", "z")
asym = symbol(letter * "axis")
for arg in wraptuple(pop!(d, asym, ()))
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
#
# ssym = symbol(letter * "scale")
# if haskey(d, ssym) && haskey(_scaleAliases, d[ssym])
# d[ssym] = _scaleAliases[d[ssym]]
# end
end
# # handle axis args
# for letter in ("x", "y", "z")
# asym = symbol(letter * "axis")
# for arg in wraptuple(pop!(d, asym, ()))
# 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
# #
# # ssym = symbol(letter * "scale")
# # if haskey(d, ssym) && haskey(_scaleAliases, d[ssym])
# # d[ssym] = _scaleAliases[d[ssym]]
# # end
# end
# handle line args
for arg in wraptuple(pop!(d, :line, ()))
@ -668,18 +669,18 @@ function preprocessArgs!(d::KW)
delete!(d, :link)
end
# pull out invalid keywords into their own KW dict... these are likely user-defined through recipes
kw = KW()
for k in keys(d)
try
# this should error for invalid keywords (assume they are user-defined)
k == :markershape_to_add || default(k)
catch
# not a valid key... pop and add to user list
kw[k] = pop!(d, k)
end
end
kw
# # pull out invalid keywords into their own KW dict... these are likely user-defined through recipes
# kw = KW()
# for k in keys(d)
# try
# # this should error for invalid keywords (assume they are user-defined)
# k == :markershape_to_add || default(k)
# catch
# # not a valid key... pop and add to user list
# kw[k] = pop!(d, k)
# end
# end
# kw
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])
function warnOnUnsupported(pkg::AbstractBackend, d::KW)
(d[:axis] in supportedAxes(pkg)
|| warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
# (d[:axis] in supportedAxes(pkg)
# || warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
(d[:seriestype] == :none
|| d[:seriestype] in 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.
# 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)
if haskey(d_in, k) && !(typeof(d_in[k]) <: Union{AbstractMatrix, Tuple} && isempty(d_in[k]))
d_out[k] = getArgValue(d_in[k], idx)
else
d_out[k] = deepcopy(defaults[k])
end
end
# # 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.
# 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]))
# d_out[k] = slice_arg(d_in[k], idx)
# else
# d_out[k] = deepcopy(defaults[k])
# end
# end
function convertLegendValue(val::Symbol)
if val in (:both, :all, :yes)
@ -806,40 +795,140 @@ convertLegendValue(val::Bool) = val ? :best : :none
# -----------------------------------------------------------------------------
# build the argument dictionary for the plot
function getPlotArgs(pkg::AbstractBackend, kw, idx::Int; set_defaults = true)
kwdict = KW(kw)
d = KW()
# function getPlotArgs(pkg::AbstractBackend, kw, idx::Int; set_defaults = true)
# d_in = KW(kw)
# d_out = KW()
#
# # add defaults?
# if set_defaults
# for k in keys(_plot_defaults)
# setDictValue(d_in, d_out, k, idx, _plot_defaults)
# 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
# add defaults?
if set_defaults
for k in keys(_plot_defaults)
setDictValue(kwdict, d, k, idx, _plot_defaults)
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
#
# for k in (:xscale, :yscale)
# if haskey(_scaleAliases, d[k])
# d[k] = _scaleAliases[d[k]]
# end
# end
# handle legend/colorbar
d[:legend] = convertLegendValue(d[:legend])
d[:colorbar] = convertLegendValue(d[:colorbar])
if d[:colorbar] == :legend
d[:colorbar] = d[:legend]
spargs[:legend] = convertLegendValue(spargs[:legend])
spargs[:colorbar] = convertLegendValue(spargs[:colorbar])
if spargs[:colorbar] == :legend
spargs[:colorbar] = spargs[:legend]
end
# convert color
handlePlotColors(pkg, d)
# background colors
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
delete!(d, :x)
delete!(d, :y)
# foreground colors
fg = color_or_match!(spargs, :foreground_color_subplot, pargs[:foreground_color])
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
# update the axis
update!(axis, args...; kw...)
end
end
function has_black_border_for_default(st::Symbol)
like_histogram(st) || st in (:hexbin, :bar)
end

View File

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

View File

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

View File

@ -173,10 +173,10 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
end
function handlePlotColors(::UnicodePlotsBackend, d::KW)
# 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)]
end
# function handlePlotColors(::UnicodePlotsBackend, d::KW)
# # 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)]
# end
# -------------------------------
@ -189,6 +189,7 @@ function _create_backend_figure(plt::Plot{UnicodePlotsBackend})
if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == default(:size)
plt.plotargs[:size] = (60,20)
end
plt.plotargs[:color_palette] = [RGB(0,0,0)]
nothing
# plt

View File

@ -294,7 +294,7 @@ function generate_colorgradient(bgcolor = colorant"white";
gradient_from_list(colors)
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
generate_colorgradient(bgcolor)
else
@ -304,7 +304,8 @@ function get_color_palette(palette, bgcolor::@compat(Union{Colorant,ColorWrapper
RGBA[getColorZ(grad, z) for z in zrng]
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
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?
function handlePlotColors(::AbstractBackend, d::KW)
if :background_color in supportedArgs()
bgcolor = convertColor(d[:background_color])
else
bgcolor = default(:background_color)
if d[:background_color] != default(:background_color)
warn("Cannot set background_color with backend $(backend())")
end
end
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
# on how dark the background is.
fgcolor = get(d, :foreground_color, :auto)
fgcolor = if fgcolor == :auto
isdark(bgcolor) ? colorant"white" : colorant"black"
else
convertColor(fgcolor)
end
# bg/fg color
d[:background_color] = colorscheme(bgcolor)
d[:foreground_color] = colorscheme(fgcolor)
# update sub-background colors
for bgtype in ("legend", "inside", "outside")
bgsym = symbol("background_color_" * bgtype)
if d[bgsym] == :match
d[bgsym] = d[:background_color]
elseif d[bgsym] == nothing
d[bgsym] = colorscheme(RGBA(0,0,0,0))
end
end
# update sub-foreground colors
for fgtype in ("legend", "grid", "axis", "text", "border", "guide")
fgsym = symbol("foreground_color_" * fgtype)
if d[fgsym] == :match
d[fgsym] = d[:foreground_color]
elseif d[fgsym] == nothing
d[fgsym] = colorscheme(RGBA(0,0,0,0))
end
end
end
# function handlePlotColors(::AbstractBackend, d::KW)
# if :background_color in supportedArgs()
# bgcolor = convertColor(d[:background_color])
# else
# bgcolor = default(:background_color)
# if d[:background_color] != default(:background_color)
# warn("Cannot set background_color with backend $(backend())")
# end
# end
#
#
# 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
# # on how dark the background is.
# fgcolor = get(d, :foreground_color, :auto)
# fgcolor = if fgcolor == :auto
# isdark(bgcolor) ? colorant"white" : colorant"black"
# else
# convertColor(fgcolor)
# end
#
# # bg/fg color
# d[:background_color] = colorscheme(bgcolor)
# d[:foreground_color] = colorscheme(fgcolor)
#
# # update sub-background colors
# for bgtype in ("legend", "inside", "outside")
# bgsym = symbol("background_color_" * bgtype)
# if d[bgsym] == :match
# d[bgsym] = d[:background_color]
# elseif d[bgsym] == nothing
# d[bgsym] = colorscheme(RGBA(0,0,0,0))
# end
# end
#
# # update sub-foreground colors
# for fgtype in ("legend", "grid", "axis", "text", "border", "guide")
# fgsym = symbol("foreground_color_" * fgtype)
# if d[fgsym] == :match
# d[fgsym] = d[:foreground_color]
# elseif d[fgsym] == nothing
# d[fgsym] = colorscheme(RGBA(0,0,0,0))
# end
# end
#
#
# end
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, plotargs::KW, n::Int)

View File

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

View File

@ -47,22 +47,18 @@ function plot(args...; kw...)
d = KW(kw)
preprocessArgs!(d)
# subplots = Subplot[layout] # TODO: build full list
# smap = SubplotMap(1 => layout) # TODO: actually build a map
# TODO: this seems wrong... I only call getPlotArgs when creating a new plot??
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)
# 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)
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
@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)
@show sp.o
end
# now update the plot
@ -94,58 +90,58 @@ 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
# handle axis updates from a recipe
for letter in ("x","y","z")
# get the Axis object
asym = symbol(letter * "axis")
axis = plt.plotargs[asym]
if axis == nothing
# create a new one on first pass
axis = Axis(letter)
end
# @show 1,typeof(axis)
# update xlabel, xscale, etc
for k in _axis_symbols
lk = symbol(letter * string(k))
if haskey(d, lk)
axis[k] = d[lk]
end
end
# @show 2,axis
# update guidefont, etc
for k in _axis_symbols_fonts_colors
if haskey(d, k)
axis[k] = d[k]
end
end
# @show 3,axis
# update extrema and discrete values
datasym = symbol(letter)
if haskey(d, datasym)
v = d[datasym]
if eltype(v) <: Number
expand_extrema!(axis, v)
else
d[datasym] = discrete_value!(axis, v)
end
end
# @show 4,axis
end
for k in keys(_plot_defaults)
if haskey(d, k)
plt.plotargs[k] = pop!(d, k)
end
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
#
# # handle axis updates from a recipe
# for letter in ("x","y","z")
# # get the Axis object
# asym = symbol(letter * "axis")
# axis = plt.plotargs[asym]
# if axis == nothing
# # create a new one on first pass
# axis = Axis(letter)
# end
# # @show 1,typeof(axis)
#
# # update xlabel, xscale, etc
# for k in _axis_symbols
# lk = symbol(letter * string(k))
# if haskey(d, lk)
# axis[k] = d[lk]
# end
# end
# # @show 2,axis
#
# # update guidefont, etc
# for k in _axis_symbols_fonts_colors
# if haskey(d, k)
# axis[k] = d[k]
# end
# end
# # @show 3,axis
#
# # update extrema and discrete values
# datasym = symbol(letter)
# if haskey(d, datasym)
# v = d[datasym]
# if eltype(v) <: Number
# expand_extrema!(axis, v)
# else
# d[datasym] = discrete_value!(axis, v)
# end
# end
# # @show 4,axis
# end
#
# for k in keys(_plot_defaults)
# if haskey(d, k)
# plt.plotargs[k] = pop!(d, k)
# end
# end
# end
# this method recursively applies series recipes when the seriestype is not supported
# natively by the backend
@ -154,11 +150,32 @@ function _apply_series_recipe(plt::Plot, d::KW)
# dumpdict(d, "apply_series_recipe", true)
if st in supportedTypes()
# 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)
series = Series(d)
push!(plt.series_list, series)
# _add_series(plt.backend, plt, d)
_add_series(plt, series)
else
# get a sub list of series for this seriestype
series_list = try
@ -275,15 +292,17 @@ function _plot!(plt::Plot, d::KW, args...)
# @show typeof((kw[:x], kw[:y], kw[:z]))
# end
# merge plot args... this is where we combine all the plot args from the user and
# from the recipes... axis info, colors, etc
# TODO: why do i need to check for the subplot key?
# if !haskey(d, :subplot)
for kw in vcat(kw_list, d)
_add_plotargs!(plt, kw)
end
handlePlotColors(plt.backend, plt.plotargs)
# # merge plot args... this is where we combine all the plot args from the user and
# # from the recipes... axis info, colors, etc
# # TODO: why do i need to check for the subplot key?
# # if !haskey(d, :subplot)
# # for kw in vcat(kw_list, d)
# for kw in kw_list
# _update_subplot_args(plt, kw[:subplot], kw)
# # _add_plotargs!(plt, kw)
# end
# # handlePlotColors(plt.backend, plt.plotargs)
# # end
# for kw in kw_list
# @show typeof((kw[:x], kw[:y], kw[:z]))
@ -296,10 +315,20 @@ function _plot!(plt::Plot, d::KW, args...)
plt.n += 1
end
# set default values, select from attribute cycles, and generally set the final attributes
_add_defaults!(kw, plt, i)
# get the Subplot object to which the series belongs
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
# 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
function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
pkg = plt.backend
n = plt.n
plotargs = getplotargs(plt, n)
plotIndex = convertSeriesIndex(plt, n)
globalIndex = n
# n = plt.n
# plotargs = getplotargs(plt, n)
# plotIndex = convertSeriesIndex(plt, n)
globalIndex = plt.n
# add defaults?
for k in keys(_series_defaults)
setDictValue(d, d, k, commandIndex, _series_defaults)
# # add defaults?
# for k in keys(_series_defaults)
# setDictValue(d, d, k, commandIndex, _series_defaults)
# end
for (k,v) in _series_defaults
slice_arg!(d, d, k, v, commandIndex)
end
if d[:subplot] == :auto
# TODO: something useful
d[:subplot] = 1
end
# this is how many series belong to this subplot
plotIndex = count(series -> series.d[:subplot] === sp, plt.series_list)
aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex)
# aliasesAndAutopick(d, :axis, _axesAliases, supportedAxes(pkg), plotIndex)
aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
# update color
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], plotargs, plotIndex)
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], sp.subplotargs, plotIndex)
# update colors
for csym in (:linecolor, :markercolor, :fillcolor)
@ -35,13 +36,17 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
d[:seriescolor]
end
else
getSeriesRGBColor(d[csym], plotargs, plotIndex)
getSeriesRGBColor(d[csym], sp.subplotargs, plotIndex)
end
end
# update 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
# update alphas
@ -62,11 +67,12 @@ function _add_defaults!(d::KW, plt::Plot, commandIndex::Int)
# set label
label = d[:label]
label = (label == "AUTO" ? "y$globalIndex" : label)
if d[:axis] == :right && !(length(label) >= 4 && label[end-3:end] != " (R)")
label = string(label, " (R)")
end
# if d[:axis] == :right && !(length(label) >= 4 && label[end-3:end] != " (R)")
# label = string(label, " (R)")
# end
d[:label] = label
_replace_linewidth(d)
d
end

View File

@ -223,6 +223,7 @@ end
get_subplot(plt::Plot, sp::Subplot) = sp
get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
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
end
function Plot(plotargs::KW)
Plot(backend(), 0, plotargs, Series[], nothing, Subplot[], SubplotMap(), EmptyLayout())
function Plot()
Plot(backend(), 0, KW(), Series[], nothing,
Subplot[], SubplotMap(), EmptyLayout())
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) = :invalid
axis_symbol(letter, postfix) = symbol(letter * postfix)
axis_symbols(letter, postfix...) = map(s -> axis_symbol(letter, s), postfix)
# axis_symbol(letter, postfix) = symbol(letter * 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,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng]