colorbar layout fixes; process_axis_arg and related fix

This commit is contained in:
Thomas Breloff 2016-05-21 00:04:33 -04:00
parent 862ac3af8a
commit 4a96122067
3 changed files with 150 additions and 85 deletions

View File

@ -613,26 +613,29 @@ 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, ())) args = pop!(d, asym, ())
# processAxisArg(d, letter, arg) if !(typeof(args) <: Axis)
# end for arg in wraptuple(args)
# # delete!(d, asym) process_axis_arg!(d, arg, letter)
# end
# # # NOTE: this logic was moved to _add_plotargs... end
# # # turn :labels into :ticks_and_labels # delete!(d, asym)
# # tsym = symbol(letter * "ticks")
# # if haskey(d, tsym) && ticksType(d[tsym]) == :labels # # NOTE: this logic was moved to _add_plotargs...
# # d[tsym] = (1:length(d[tsym]), d[tsym]) # # turn :labels into :ticks_and_labels
# # end # tsym = symbol(letter * "ticks")
# # # if haskey(d, tsym) && ticksType(d[tsym]) == :labels
# # ssym = symbol(letter * "scale") # d[tsym] = (1:length(d[tsym]), d[tsym])
# # if haskey(d, ssym) && haskey(_scaleAliases, d[ssym]) # end
# # d[ssym] = _scaleAliases[d[ssym]] #
# # end # ssym = symbol(letter * "scale")
# end # if haskey(d, ssym) && haskey(_scaleAliases, d[ssym])
# d[ssym] = _scaleAliases[d[ssym]]
# end
end
# # if title is just a single string, then assume we want plot_title # # if title is just a single string, then assume we want plot_title
# # TODO: make a decision if this is correct # # TODO: make a decision if this is correct

View File

@ -21,46 +21,50 @@ function Axis(letter::Symbol, args...; kw...)
update!(Axis(d), args...; kw...) update!(Axis(d), args...; kw...)
end end
function process_axis_arg!(d::KW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font
d[symbol(letter,:tickfont)] = arg
d[symbol(letter,:guidefont)] = arg
elseif arg in _allScales
d[symbol(letter,:scale)] = arg
elseif arg in (:flip, :invert, :inverted)
d[symbol(letter,:flip)] = true
elseif T <: @compat(AbstractString)
d[symbol(letter,:guide)] = arg
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
sym = typeof(arg[1]) <: Number ? :lims : :ticks
d[symbol(letter,sym)] = arg
# xticks/yticks
elseif T <: AVec
d[symbol(letter,:ticks)] = arg
elseif arg == nothing
d[symbol(letter,:ticks)] = []
elseif typeof(arg) <: Number
d[symbol(letter,:rotation)] = arg
else
warn("Skipped $(letter)axis arg $arg")
end
end
# update an Axis object with magic args and keywords # update an Axis object with magic args and keywords
function update!(a::Axis, args...; kw...) function update!(a::Axis, args...; kw...)
# first process args # first process args
d = a.d d = a.d
for arg in args for arg in args
T = typeof(arg) process_axis_arg!(d, arg)
arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font
d[:tickfont] = arg
d[:guidefont] = arg
elseif arg in _allScales
d[:scale] = arg
elseif arg in (:flip, :invert, :inverted)
d[:flip] = true
elseif T <: @compat(AbstractString)
d[:guide] = arg
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
sym = typeof(arg[1]) <: Number ? :lims : :ticks
d[sym] = arg
# xticks/yticks
elseif T <: AVec
d[:ticks] = arg
elseif arg == nothing
d[:ticks] = []
elseif typeof(arg) <: Number
d[:rotation] = arg
else
warn("Skipped $(letter)axis arg $arg")
end
end end
# then override for any keywords... only those keywords that already exists in d # then override for any keywords... only those keywords that already exists in d

View File

@ -267,22 +267,31 @@ function py_bbox(obj)
BoundingBox(l*px, (ft-t)*px, (r-l)*px, (t-b)*px) BoundingBox(l*px, (ft-t)*px, (r-l)*px, (t-b)*px)
end end
# get the bounding box of the union of the objects
function py_bbox(v::AVec)
bbox_union = defaultbox
for obj in v
bbox_union = bbox_union + py_bbox(obj)
end
bbox_union
end
function py_bbox_ticks(ax, letter) function py_bbox_ticks(ax, letter)
# fig = ax[:get_figure]() # fig = ax[:get_figure]()
# @show fig # @show fig
labels = ax[symbol("get_"*letter*"ticklabels")]() labels = ax[symbol("get_"*letter*"ticklabels")]()
# @show labels py_bbox(labels)
# bboxes = [] # # @show labels
bbox_union = defaultbox # # bboxes = []
for lab in labels # bbox_union = defaultbox
# @show lab,lab[:get_text]() # for lab in labels
bbox = py_bbox(lab) # # @show lab,lab[:get_text]()
bbox_union = bbox_union + bbox # bbox = py_bbox(lab)
# @show letter,bbox bbox_union # bbox_union = bbox_union + bbox
# @show bbox_union # # @show letter,bbox bbox_union
end # # @show bbox_union
bbox_union # end
# bbox_union
end end
function py_bbox_axislabel(ax, letter) function py_bbox_axislabel(ax, letter)
@ -316,6 +325,8 @@ min_padding_top(layout::Subplot{PyPlotBackend}) = compute_min_padding(layout,
min_padding_right(layout::Subplot{PyPlotBackend}) = compute_min_padding(layout, right, -1) min_padding_right(layout::Subplot{PyPlotBackend}) = compute_min_padding(layout, right, -1)
min_padding_bottom(layout::Subplot{PyPlotBackend}) = compute_min_padding(layout, bottom,-1) min_padding_bottom(layout::Subplot{PyPlotBackend}) = compute_min_padding(layout, bottom,-1)
const _cbar_width = 5mm
# loop over the guides and axes and compute how far they "stick out" from the plot area, # loop over the guides and axes and compute how far they "stick out" from the plot area,
# so that we know the minimum padding we need to avoid cropping and overlapping text. # so that we know the minimum padding we need to avoid cropping and overlapping text.
# `func` is one of (left,top,right,bottom), and we multiply by 1 or -1 depending on direction # `func` is one of (left,top,right,bottom), and we multiply by 1 or -1 depending on direction
@ -337,6 +348,14 @@ function compute_min_padding(sp::Subplot{PyPlotBackend}, func::Function, mult::N
# @show padding # @show padding
end end
if func == right && haskey(sp.attr, :cbar_ax)
# TODO: need bounding box of colorbar labels
# bb = py_bbox(sp.attr[:cbar_ax][:get_ticklabels]())
bb = BoundingBox(0mm,0mm,15mm,15mm)
sp.attr[:cbar_width] = _cbar_width + width(bb)
padding = padding + sp.attr[:cbar_width]
end
# if func == top # if func == top
# titlebbox = py_bbox_title(ax) # titlebbox = py_bbox_title(ax)
# padding = max(padding, height(titlebbox)) # padding = max(padding, height(titlebbox))
@ -374,24 +393,47 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# TODO: add this (and _cbar_width) to layouts.jl?
function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
mms = Float64[f(bb).value for f in (left,bottom,width,height)]
if flipy
mms[2] = figh.value - mms[2] # flip y when origin in bottom-left
end
mms ./ Float64[figw.value, figh.value, figw.value, figh.value]
end
function update_position!(sp::Subplot{PyPlotBackend}) function update_position!(sp::Subplot{PyPlotBackend})
ax = sp.o ax = sp.o
ax == nothing && return ax == nothing && return
figw, figh = size(py_bbox_fig(sp.plt)) figw, figh = size(py_bbox_fig(sp.plt))
# plot_bb = plotarea_bbox(sp) # plot_bb = plotarea_bbox(sp)
plot_bb = sp.plotarea # plot_bb = sp.plotarea
# @show sp.bbox plot_bb # @show sp.bbox plot_bb
# l = float(left(plot_bb) / px) / figw # l = float(left(plot_bb) / px) / figw
# b = float(bottom(plot_bb) / px) / figh # b = float(bottom(plot_bb) / px) / figh
# w = float(width(plot_bb) / px) / figw # w = float(width(plot_bb) / px) / figw
mms = Float64[f(plot_bb).value for f in (left, bottom, width, height)] # mms = Float64[f(plot_bb).value for f in (left, bottom, width, height)]
#
mms[2] = figh.value - mms[2] # mms[2] = figh.value - mms[2]
# @show mms # # @show mms
pcts = mms ./ Float64[figw.value, figh.value, figw.value, figh.value] # pcts = mms ./ Float64[figw.value, figh.value, figw.value, figh.value]
pcts = bbox_to_pcts(sp.plotarea, figw, figh)
# @show pcts # @show pcts
ax[:set_position](pcts) ax[:set_position](pcts)
# set the cbar position if there is one
# @show sp.attr[:cbar_ax]
if haskey(sp.attr, :cbar_ax)
cbw = sp.attr[:cbar_width]
# cb_bbox = BoundingBox(figw - cbw, 0.1figh, cbw, figh - 0.2pct)
# this is the bounding box of just the colors of the colorbar (not labels)
cb_bbox = BoundingBox(right(sp.bbox)-cbw+2mm, top(sp.bbox)+2mm, _cbar_width, height(sp.bbox)-4mm)
pcts = bbox_to_pcts(cb_bbox, figw, figh)
# @show cbw cb_bbox pcts
sp.attr[:cbar_ax][:set_position](pcts)
end
end end
# each backend should set up the subplot here # each backend should set up the subplot here
@ -935,24 +977,40 @@ function _add_series(plt::Plot{PyPlotBackend}, series::Series)
handleSmooth(plt, ax, d, d[:smooth]) handleSmooth(plt, ax, d, d[:smooth])
# add the colorbar legend # add the colorbar legend
if needs_colorbar && attr(d[:subplot], :colorbar) != :none sp = d[:subplot]
if needs_colorbar && sp.attr[:colorbar] != :none
# cbar = PyPlot.colorbar(handles[end], ax=ax) # cbar = PyPlot.colorbar(handles[end], ax=ax)
# do we need a discrete colorbar? # do we need a discrete colorbar?
if discrete_colorbar_values == nothing handle = handles[end]
PyPlot.colorbar(handles[end], ax=ax) kw = KW()
else if discrete_colorbar_values != nothing
# add_pyfixedformatter(cbar, discrete_colorbar_values)
locator, formatter = get_locator_and_formatter(discrete_colorbar_values) locator, formatter = get_locator_and_formatter(discrete_colorbar_values)
vals = 1:length(discrete_colorbar_values) kw[:values] = 1:length(discrete_colorbar_values)
PyPlot.colorbar(handles[end], kw[:ticks] = locator
ax = ax, kw[:format] = formatter
ticks = locator, kw[:boundaries] = vcat(0, kw[:values] + 0.5)
format = formatter,
boundaries = vcat(0, vals + 0.5),
values = vals
)
end end
fig = plt.o
cbax = fig[:add_axes]([0.8,0.1,0.03,0.8])
sp.attr[:cbar_handle] = fig[:colorbar](handle, cax = cbax, kw...)
sp.attr[:cbar_ax] = cbax
# if discrete_colorbar_values == nothing
# PyPlot.colorbar(handles[end], ax=ax)
# else
# # add_pyfixedformatter(cbar, discrete_colorbar_values)
# locator, formatter = get_locator_and_formatter(discrete_colorbar_values)
# vals = 1:length(discrete_colorbar_values)
# PyPlot.colorbar(handles[end],
# ax = ax,
# ticks = locator,
# format = formatter,
# boundaries = vcat(0, vals + 0.5),
# values = vals
# )
# end
end end
# this sets the bg color inside the grid # this sets the bg color inside the grid