gr heatmap fix; pipeline reorg
This commit is contained in:
parent
b2dba8af73
commit
8d5b748b09
@ -640,7 +640,15 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
|
|
||||||
# recompute data
|
# recompute data
|
||||||
if typeof(z) <: Surface
|
if typeof(z) <: Surface
|
||||||
# if st in (:contour, :surface, :wireframe)
|
if st == :heatmap #&& size(z.surf) == (length(y), length(x))
|
||||||
|
expand_extrema!(sp[:xaxis], (x[1]-0.5*(x[2]-x[1]), x[end]+0.5*(x[end]-x[end-1])))
|
||||||
|
expand_extrema!(sp[:yaxis], (y[1]-0.5*(y[2]-y[1]), y[end]+0.5*(y[end]-y[end-1])))
|
||||||
|
# # coords are centers... turn into edges
|
||||||
|
# xd = diff(x)
|
||||||
|
# x = vcat(x[1]-0.5xd[1], x[1]+xd, x[end]+0.5xd[end])
|
||||||
|
# yd = diff(y)
|
||||||
|
# y = vcat(y[1]-0.5yd[1], y[1]+yd, y[end]+0.5yd[end])
|
||||||
|
end
|
||||||
z = vec(transpose_z(series, z.surf, false))
|
z = vec(transpose_z(series, z.surf, false))
|
||||||
elseif ispolar(sp)
|
elseif ispolar(sp)
|
||||||
if frng != nothing
|
if frng != nothing
|
||||||
@ -718,10 +726,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
cmap && gr_colorbar(sp)
|
cmap && gr_colorbar(sp)
|
||||||
|
|
||||||
elseif st == :heatmap
|
elseif st == :heatmap
|
||||||
z = vec(transpose_z(series, z.surf, false))
|
# z = vec(transpose_z(series, z.surf, false))
|
||||||
zmin, zmax = gr_lims(zaxis, true)
|
zmin, zmax = gr_lims(zaxis, true)
|
||||||
GR.setspace(zmin, zmax, 0, 90)
|
GR.setspace(zmin, zmax, 0, 90)
|
||||||
GR.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
# GR.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
||||||
|
GR.surface(x, y, z, GR.OPTION_HEATMAP)
|
||||||
cmap && gr_colorbar(sp)
|
cmap && gr_colorbar(sp)
|
||||||
|
|
||||||
elseif st in (:path3d, :scatter3d)
|
elseif st in (:path3d, :scatter3d)
|
||||||
|
|||||||
321
src/pipeline.jl
321
src/pipeline.jl
@ -1,105 +1,7 @@
|
|||||||
|
|
||||||
# getting ready to add the series... last update to subplot from anything
|
|
||||||
# that might have been added during series recipes
|
|
||||||
function _prepare_subplot{T}(plt::Plot{T}, d::KW)
|
|
||||||
st::Symbol = d[:seriestype]
|
|
||||||
sp::Subplot{T} = d[:subplot]
|
|
||||||
sp_idx = get_subplot_index(plt, sp)
|
|
||||||
_update_subplot_args(plt, sp, d, sp_idx, true)
|
|
||||||
|
|
||||||
st = _override_seriestype_check(d, st)
|
# ------------------------------------------------------------------
|
||||||
|
# preprocessing
|
||||||
# change to a 3d projection for this subplot?
|
|
||||||
if is3d(st)
|
|
||||||
sp.attr[:projection] = "3d"
|
|
||||||
end
|
|
||||||
|
|
||||||
# initialize now that we know the first series type
|
|
||||||
if !haskey(sp.attr, :init)
|
|
||||||
_initialize_subplot(plt, sp)
|
|
||||||
sp.attr[:init] = true
|
|
||||||
end
|
|
||||||
sp
|
|
||||||
end
|
|
||||||
|
|
||||||
function _override_seriestype_check(d::KW, st::Symbol)
|
|
||||||
# do we want to override the series type?
|
|
||||||
if !is3d(st)
|
|
||||||
z = d[:z]
|
|
||||||
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
|
|
||||||
st = (st == :scatter ? :scatter3d : :path3d)
|
|
||||||
d[:seriestype] = st
|
|
||||||
end
|
|
||||||
end
|
|
||||||
st
|
|
||||||
end
|
|
||||||
|
|
||||||
function _prepare_annotations(sp::Subplot, d::KW)
|
|
||||||
# strip out series annotations (those which are based on series x/y coords)
|
|
||||||
# and add them to the subplot attr
|
|
||||||
sp_anns = annotations(sp[:annotations])
|
|
||||||
anns = annotations(pop!(d, :series_annotations, []))
|
|
||||||
if length(anns) > 0
|
|
||||||
x, y = d[:x], d[:y]
|
|
||||||
nx, ny, na = map(length, (x,y,anns))
|
|
||||||
n = max(nx, ny, na)
|
|
||||||
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
|
|
||||||
end
|
|
||||||
sp.attr[:annotations] = vcat(sp_anns, anns)
|
|
||||||
end
|
|
||||||
|
|
||||||
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
|
||||||
# adjust extrema and discrete info
|
|
||||||
if st == :image
|
|
||||||
w, h = size(d[:z])
|
|
||||||
expand_extrema!(sp[:xaxis], (0,w))
|
|
||||||
expand_extrema!(sp[:yaxis], (0,h))
|
|
||||||
sp[:yaxis].d[:flip] = true
|
|
||||||
elseif !(st in (:pie, :histogram, :histogram2d))
|
|
||||||
expand_extrema!(sp, d)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function _add_the_series(plt, d)
|
|
||||||
warnOnUnsupported_args(plt.backend, d)
|
|
||||||
warnOnUnsupported(plt.backend, d)
|
|
||||||
series = Series(d)
|
|
||||||
push!(plt.series_list, series)
|
|
||||||
_series_added(plt, series)
|
|
||||||
end
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# this method recursively applies series recipes when the seriestype is not supported
|
|
||||||
# natively by the backend
|
|
||||||
function _process_seriesrecipe(plt::Plot, d::KW)
|
|
||||||
# replace seriestype aliases
|
|
||||||
st = Symbol(d[:seriestype])
|
|
||||||
st = d[:seriestype] = get(_typeAliases, st, st)
|
|
||||||
|
|
||||||
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
|
|
||||||
if st in supported_types()
|
|
||||||
sp = _prepare_subplot(plt, d)
|
|
||||||
_prepare_annotations(sp, d)
|
|
||||||
_expand_subplot_extrema(sp, d, st)
|
|
||||||
_add_the_series(plt, d)
|
|
||||||
|
|
||||||
else
|
|
||||||
# get a sub list of series for this seriestype
|
|
||||||
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
|
|
||||||
|
|
||||||
# assuming there was no error, recursively apply the series recipes
|
|
||||||
for data in datalist
|
|
||||||
if isa(data, RecipeData)
|
|
||||||
_process_seriesrecipe(plt, data.d)
|
|
||||||
else
|
|
||||||
warn("Unhandled recipe: $(data)")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
function command_idx(kw_list::AVec{KW}, kw::KW)
|
function command_idx(kw_list::AVec{KW}, kw::KW)
|
||||||
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
||||||
@ -149,6 +51,62 @@ function _preprocess_args(d::KW, args, still_to_process::Vector{RecipeData})
|
|||||||
args
|
args
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# user recipes
|
||||||
|
|
||||||
|
|
||||||
|
function _process_userrecipes(plt::Plot, d::KW, args)
|
||||||
|
still_to_process = RecipeData[]
|
||||||
|
args = _preprocess_args(d, args, still_to_process)
|
||||||
|
|
||||||
|
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||||
|
# we are keeping a queue of series that still need to be processed.
|
||||||
|
# each pass through the loop, we pop one off and apply the recipe.
|
||||||
|
# the recipe will return a list a Series objects... the ones that are
|
||||||
|
# finished (no more args) get added to the kw_list, and the rest go into the queue
|
||||||
|
# for processing.
|
||||||
|
kw_list = KW[]
|
||||||
|
while !isempty(still_to_process)
|
||||||
|
# grab the first in line to be processed and pass it through apply_recipe
|
||||||
|
# to generate a list of RecipeData objects (data + attributes)
|
||||||
|
next_series = shift!(still_to_process)
|
||||||
|
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
||||||
|
for recipedata in rd_list
|
||||||
|
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
|
||||||
|
if !(typeof(recipedata) <: RecipeData)
|
||||||
|
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
|
||||||
|
end
|
||||||
|
|
||||||
|
if isempty(recipedata.args)
|
||||||
|
_process_userrecipe(plt, kw_list, recipedata)
|
||||||
|
else
|
||||||
|
# args are non-empty, so there's still processing to do... add it back to the queue
|
||||||
|
push!(still_to_process, recipedata)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# don't allow something else to handle it
|
||||||
|
d[:smooth] = false
|
||||||
|
kw_list
|
||||||
|
end
|
||||||
|
|
||||||
|
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
|
||||||
|
# when the arg tuple is empty, that means there's nothing left to recursively
|
||||||
|
# process... finish up and add to the kw_list
|
||||||
|
kw = recipedata.d
|
||||||
|
_preprocess_userrecipe(kw)
|
||||||
|
warnOnUnsupported_scales(plt.backend, kw)
|
||||||
|
|
||||||
|
# add the plot index
|
||||||
|
plt.n += 1
|
||||||
|
kw[:series_plotindex] = plt.n
|
||||||
|
|
||||||
|
push!(kw_list, kw)
|
||||||
|
_add_errorbar_kw(kw_list, kw)
|
||||||
|
_add_smooth_kw(kw_list, kw)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
function _preprocess_userrecipe(kw::KW)
|
function _preprocess_userrecipe(kw::KW)
|
||||||
_add_markershape(kw)
|
_add_markershape(kw)
|
||||||
@ -207,58 +165,8 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _process_userrecipes(plt::Plot, d::KW, args)
|
# ------------------------------------------------------------------
|
||||||
still_to_process = RecipeData[]
|
# plot recipes
|
||||||
args = _preprocess_args(d, args, still_to_process)
|
|
||||||
|
|
||||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
|
||||||
# we are keeping a queue of series that still need to be processed.
|
|
||||||
# each pass through the loop, we pop one off and apply the recipe.
|
|
||||||
# the recipe will return a list a Series objects... the ones that are
|
|
||||||
# finished (no more args) get added to the kw_list, and the rest go into the queue
|
|
||||||
# for processing.
|
|
||||||
kw_list = KW[]
|
|
||||||
while !isempty(still_to_process)
|
|
||||||
# grab the first in line to be processed and pass it through apply_recipe
|
|
||||||
# to generate a list of RecipeData objects (data + attributes)
|
|
||||||
next_series = shift!(still_to_process)
|
|
||||||
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
|
||||||
for recipedata in rd_list
|
|
||||||
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
|
|
||||||
if !(typeof(recipedata) <: RecipeData)
|
|
||||||
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
|
|
||||||
end
|
|
||||||
|
|
||||||
if isempty(recipedata.args)
|
|
||||||
_process_userrecipe(plt, kw_list, recipedata)
|
|
||||||
else
|
|
||||||
# args are non-empty, so there's still processing to do... add it back to the queue
|
|
||||||
push!(still_to_process, recipedata)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# don't allow something else to handle it
|
|
||||||
d[:smooth] = false
|
|
||||||
kw_list
|
|
||||||
end
|
|
||||||
|
|
||||||
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
|
|
||||||
# when the arg tuple is empty, that means there's nothing left to recursively
|
|
||||||
# process... finish up and add to the kw_list
|
|
||||||
kw = recipedata.d
|
|
||||||
_preprocess_userrecipe(kw)
|
|
||||||
warnOnUnsupported_scales(plt.backend, kw)
|
|
||||||
|
|
||||||
# add the plot index
|
|
||||||
plt.n += 1
|
|
||||||
kw[:series_plotindex] = plt.n
|
|
||||||
|
|
||||||
push!(kw_list, kw)
|
|
||||||
_add_errorbar_kw(kw_list, kw)
|
|
||||||
_add_smooth_kw(kw_list, kw)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
# Grab the first in line to be processed and pass it through apply_recipe
|
# Grab the first in line to be processed and pass it through apply_recipe
|
||||||
# to generate a list of RecipeData objects (data + attributes).
|
# to generate a list of RecipeData objects (data + attributes).
|
||||||
@ -290,6 +198,10 @@ function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_pr
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# setup plot and subplot
|
||||||
|
|
||||||
function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||||
# merge in anything meant for the Plot
|
# merge in anything meant for the Plot
|
||||||
for kw in kw_list, (k,v) in kw
|
for kw in kw_list, (k,v) in kw
|
||||||
@ -375,3 +287,108 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
|||||||
# do we need to link any axes together?
|
# do we need to link any axes together?
|
||||||
link_axes!(plt.layout, plt[:link])
|
link_axes!(plt.layout, plt[:link])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# getting ready to add the series... last update to subplot from anything
|
||||||
|
# that might have been added during series recipes
|
||||||
|
function _prepare_subplot{T}(plt::Plot{T}, d::KW)
|
||||||
|
st::Symbol = d[:seriestype]
|
||||||
|
sp::Subplot{T} = d[:subplot]
|
||||||
|
sp_idx = get_subplot_index(plt, sp)
|
||||||
|
_update_subplot_args(plt, sp, d, sp_idx, true)
|
||||||
|
|
||||||
|
st = _override_seriestype_check(d, st)
|
||||||
|
|
||||||
|
# change to a 3d projection for this subplot?
|
||||||
|
if is3d(st)
|
||||||
|
sp.attr[:projection] = "3d"
|
||||||
|
end
|
||||||
|
|
||||||
|
# initialize now that we know the first series type
|
||||||
|
if !haskey(sp.attr, :init)
|
||||||
|
_initialize_subplot(plt, sp)
|
||||||
|
sp.attr[:init] = true
|
||||||
|
end
|
||||||
|
sp
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# series types
|
||||||
|
|
||||||
|
function _override_seriestype_check(d::KW, st::Symbol)
|
||||||
|
# do we want to override the series type?
|
||||||
|
if !is3d(st)
|
||||||
|
z = d[:z]
|
||||||
|
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
|
||||||
|
st = (st == :scatter ? :scatter3d : :path3d)
|
||||||
|
d[:seriestype] = st
|
||||||
|
end
|
||||||
|
end
|
||||||
|
st
|
||||||
|
end
|
||||||
|
|
||||||
|
function _prepare_annotations(sp::Subplot, d::KW)
|
||||||
|
# strip out series annotations (those which are based on series x/y coords)
|
||||||
|
# and add them to the subplot attr
|
||||||
|
sp_anns = annotations(sp[:annotations])
|
||||||
|
anns = annotations(pop!(d, :series_annotations, []))
|
||||||
|
if length(anns) > 0
|
||||||
|
x, y = d[:x], d[:y]
|
||||||
|
nx, ny, na = map(length, (x,y,anns))
|
||||||
|
n = max(nx, ny, na)
|
||||||
|
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
|
||||||
|
end
|
||||||
|
sp.attr[:annotations] = vcat(sp_anns, anns)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||||
|
# adjust extrema and discrete info
|
||||||
|
if st == :image
|
||||||
|
w, h = size(d[:z])
|
||||||
|
expand_extrema!(sp[:xaxis], (0,w))
|
||||||
|
expand_extrema!(sp[:yaxis], (0,h))
|
||||||
|
sp[:yaxis].d[:flip] = true
|
||||||
|
elseif !(st in (:pie, :histogram, :histogram2d))
|
||||||
|
expand_extrema!(sp, d)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _add_the_series(plt, d)
|
||||||
|
warnOnUnsupported_args(plt.backend, d)
|
||||||
|
warnOnUnsupported(plt.backend, d)
|
||||||
|
series = Series(d)
|
||||||
|
push!(plt.series_list, series)
|
||||||
|
_series_added(plt, series)
|
||||||
|
end
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# this method recursively applies series recipes when the seriestype is not supported
|
||||||
|
# natively by the backend
|
||||||
|
function _process_seriesrecipe(plt::Plot, d::KW)
|
||||||
|
# replace seriestype aliases
|
||||||
|
st = Symbol(d[:seriestype])
|
||||||
|
st = d[:seriestype] = get(_typeAliases, st, st)
|
||||||
|
|
||||||
|
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
|
||||||
|
if st in supported_types()
|
||||||
|
sp = _prepare_subplot(plt, d)
|
||||||
|
_prepare_annotations(sp, d)
|
||||||
|
_expand_subplot_extrema(sp, d, st)
|
||||||
|
_add_the_series(plt, d)
|
||||||
|
|
||||||
|
else
|
||||||
|
# get a sub list of series for this seriestype
|
||||||
|
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
|
||||||
|
|
||||||
|
# assuming there was no error, recursively apply the series recipes
|
||||||
|
for data in datalist
|
||||||
|
if isa(data, RecipeData)
|
||||||
|
_process_seriesrecipe(plt, data.d)
|
||||||
|
else
|
||||||
|
warn("Unhandled recipe: $(data)")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nothing
|
||||||
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user