histogram2d recipe; handle smoothing generically
This commit is contained in:
parent
cf5aed00e2
commit
56f398fb55
@ -182,7 +182,7 @@ function expand_extrema!(sp::Subplot, d::KW)
|
||||
if bw == nothing
|
||||
bw = d[:bar_width] = mean(diff(data))
|
||||
end
|
||||
@show data bw
|
||||
# @show data bw
|
||||
|
||||
axis = sp.attr[Symbol(dsym, :axis)]
|
||||
expand_extrema!(axis, maximum(data) + 0.5maximum(bw))
|
||||
|
||||
@ -34,12 +34,14 @@ supportedArgs(::GRBackend) = [
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:aspect_ratio
|
||||
:aspect_ratio,
|
||||
:normalize, :weights
|
||||
]
|
||||
supportedAxes(::GRBackend) = _allAxes
|
||||
supportedTypes(::GRBackend) = [
|
||||
:path, :steppre, :steppost,
|
||||
:scatter, :histogram2d, :hexbin,
|
||||
:scatter,
|
||||
#:histogram2d, :hexbin,
|
||||
:sticks,
|
||||
# :hline, :vline,
|
||||
:heatmap, :pie, :image,
|
||||
@ -647,19 +649,26 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
for axis_idx = 1:num_axes
|
||||
xmin, xmax, ymin, ymax = extrema[axis_idx,:]
|
||||
|
||||
# NOTE: for log axes, the major_x and major_y - if non-zero (omit labels) - control the minor grid lines (1 = draw 9 minor grid lines, 2 = no minor grid lines)
|
||||
# NOTE: for log axes, the x_tick and y_tick - if non-zero (omit axes) - only affect the output appearance (1 = nomal, 2 = scientiic notation)
|
||||
if scale & GR.OPTION_X_LOG == 0
|
||||
# xmin, xmax = GR.adjustlimits(xmin, xmax)
|
||||
majorx = 5
|
||||
xtick = GR.tick(xmin, xmax) / majorx
|
||||
else
|
||||
xtick = majorx = 1
|
||||
# xtick = majorx = 1
|
||||
xtick = 2 # scientific notation
|
||||
majorx = 2 # no minor grid lines
|
||||
end
|
||||
if scale & GR.OPTION_Y_LOG == 0
|
||||
# ymin, ymax = GR.adjustlimits(ymin, ymax)
|
||||
majory = 5
|
||||
ytick = GR.tick(ymin, ymax) / majory
|
||||
else
|
||||
ytick = majory = 1
|
||||
# ytick = majory = 1
|
||||
ytick = 2 # scientific notation
|
||||
majory = 2 # no minor grid lines
|
||||
end
|
||||
xorg = (scale & GR.OPTION_FLIP_X == 0) ? (xmin,xmax) : (xmax,xmin)
|
||||
yorg = (scale & GR.OPTION_FLIP_Y == 0) ? (ymin,ymax) : (ymax,ymin)
|
||||
@ -692,12 +701,13 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
ticksize = -ticksize
|
||||
end
|
||||
if grid_flag
|
||||
@show dark_bg, xtick, ytick, majorx, majory
|
||||
if dark_bg
|
||||
GR.grid(xtick * majorx, ytick * majory, 0, 0, 1, 1)
|
||||
else
|
||||
GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
end
|
||||
GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
# @show dark_bg, xtick, ytick, majorx, majory
|
||||
# if dark_bg
|
||||
# GR.grid(xtick * majorx, ytick * majory, 0, 0, 1, 1)
|
||||
# else
|
||||
# GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
# end
|
||||
end
|
||||
# TODO: this should be done for each axis separately
|
||||
GR.setlinecolorind(gr_getcolorind(xaxis[:foreground_color_axis]))
|
||||
@ -927,32 +937,32 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
# end
|
||||
# end
|
||||
|
||||
# TODO: use recipe
|
||||
elseif st in [:histogram2d, :hexbin]
|
||||
E = zeros(length(d[:x]),2)
|
||||
E[:,1] = d[:x]
|
||||
E[:,2] = d[:y]
|
||||
if isa(d[:bins], Tuple)
|
||||
xbins, ybins = d[:bins]
|
||||
else
|
||||
xbins = ybins = d[:bins]
|
||||
end
|
||||
x, y, H = Base.hist2d(E, xbins, ybins)
|
||||
maxh = maximum(H)
|
||||
n, m = size(H)
|
||||
counts = Int32[round(Int32, 1000 + 255 * H[n-i+1,j] / maxh) for i=1:n,j=1:m]
|
||||
GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts)
|
||||
# # TODO: use recipe
|
||||
# elseif st in [:histogram2d, :hexbin]
|
||||
# E = zeros(length(d[:x]),2)
|
||||
# E[:,1] = d[:x]
|
||||
# E[:,2] = d[:y]
|
||||
# if isa(d[:bins], Tuple)
|
||||
# xbins, ybins = d[:bins]
|
||||
# else
|
||||
# xbins = ybins = d[:bins]
|
||||
# end
|
||||
# x, y, H = Base.hist2d(E, xbins, ybins)
|
||||
# maxh = maximum(H)
|
||||
# n, m = size(H)
|
||||
# counts = Int32[round(Int32, 1000 + 255 * H[n-i+1,j] / maxh) for i=1:n,j=1:m]
|
||||
# GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts)
|
||||
|
||||
# NOTE: set viewport to the colorbar area, get character height, draw it, then reset viewport
|
||||
GR.setviewport(viewport_plotarea[2] + 0.02, viewport_plotarea[2] + 0.05, viewport_plotarea[3], viewport_plotarea[4])
|
||||
# zmin, zmax = gr_getzlims(d, 0, maximum(counts), false)
|
||||
zmin, zmax = gr_lims(zaxis, false, (0, maximum(counts)))
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
diag = sqrt((viewport_plotarea[2] - viewport_plotarea[1])^2 + (viewport_plotarea[4] - viewport_plotarea[3])^2)
|
||||
charheight = max(0.016 * diag, 0.01)
|
||||
GR.setcharheight(charheight)
|
||||
GR.colormap()
|
||||
GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4])
|
||||
# # NOTE: set viewport to the colorbar area, get character height, draw it, then reset viewport
|
||||
# GR.setviewport(viewport_plotarea[2] + 0.02, viewport_plotarea[2] + 0.05, viewport_plotarea[3], viewport_plotarea[4])
|
||||
# # zmin, zmax = gr_getzlims(d, 0, maximum(counts), false)
|
||||
# zmin, zmax = gr_lims(zaxis, false, (0, maximum(counts)))
|
||||
# GR.setspace(zmin, zmax, 0, 90)
|
||||
# diag = sqrt((viewport_plotarea[2] - viewport_plotarea[1])^2 + (viewport_plotarea[4] - viewport_plotarea[3])^2)
|
||||
# charheight = max(0.016 * diag, 0.01)
|
||||
# GR.setcharheight(charheight)
|
||||
# GR.colormap()
|
||||
# GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4])
|
||||
|
||||
elseif st == :contour
|
||||
x, y, z = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
|
||||
@ -513,7 +513,7 @@ rowsize(v) = isrow(v) ? length(v.args) : 1
|
||||
|
||||
function create_grid(expr::Expr)
|
||||
# cellsym = gensym(:cell)
|
||||
@show expr
|
||||
# @show expr
|
||||
if iscol(expr)
|
||||
create_grid_vcat(expr)
|
||||
# rowsizes = map(rowsize, expr.args)
|
||||
@ -562,17 +562,17 @@ end
|
||||
function create_grid_vcat(expr::Expr)
|
||||
rowsizes = map(rowsize, expr.args)
|
||||
rmin, rmax = extrema(rowsizes)
|
||||
@show rmin, rmax
|
||||
# @show rmin, rmax
|
||||
if rmin > 0 && rmin == rmax
|
||||
# we have a grid... build the whole thing
|
||||
# note: rmin is the number of columns
|
||||
nr = length(expr.args)
|
||||
nc = rmin
|
||||
@show nr, nc
|
||||
# @show nr, nc
|
||||
body = Expr(:block)
|
||||
for r=1:nr
|
||||
arg = expr.args[r]
|
||||
@show r, arg
|
||||
# @show r, arg
|
||||
if isrow(arg)
|
||||
for (c,item) in enumerate(arg.args)
|
||||
push!(body.args, :(cell[$r,$c] = $(create_grid(item))))
|
||||
@ -581,7 +581,7 @@ function create_grid_vcat(expr::Expr)
|
||||
push!(body.args, :(cell[$r,1] = $(create_grid(arg))))
|
||||
end
|
||||
end
|
||||
@show body
|
||||
# @show body
|
||||
:(let cell = GridLayout($nr, $nc)
|
||||
$body
|
||||
cell
|
||||
@ -614,7 +614,7 @@ function create_grid_curly(expr::Expr)
|
||||
for (i,arg) in enumerate(expr.args[2:end])
|
||||
add_layout_pct!(kw, arg, i, length(expr.args)-1)
|
||||
end
|
||||
# @show kw
|
||||
@show kw
|
||||
:(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))
|
||||
end
|
||||
|
||||
|
||||
21
src/plot.jl
21
src/plot.jl
@ -278,6 +278,24 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
end
|
||||
end
|
||||
|
||||
# handle smoothing by adding a new series
|
||||
if get(d, :smooth, false)
|
||||
x, y = kw[:x], kw[:y]
|
||||
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
|
||||
sx = [minimum(x), maximum(x)]
|
||||
sy = β * sx + α
|
||||
push!(kw_list, merge(copy(kw), KW(
|
||||
:seriestype => :path,
|
||||
:x => sx,
|
||||
:y => sy,
|
||||
:fillrange => nothing,
|
||||
:label => "",
|
||||
)))
|
||||
|
||||
# don't allow something else to handle it
|
||||
d[:smooth] = false
|
||||
end
|
||||
|
||||
else
|
||||
# args are non-empty, so there's still processing to do... add it back to the queue
|
||||
push!(still_to_process, recipedata)
|
||||
@ -334,6 +352,7 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
# if !(get(kw, :seriestype, :none) in (:xerror, :yerror))
|
||||
# plt.n += 1
|
||||
# end
|
||||
command_idx = kw[:series_plotindex] - kw_list[1][:series_plotindex] + 1
|
||||
|
||||
# get the Subplot object to which the series belongs
|
||||
sp = get(kw, :subplot, :auto)
|
||||
@ -361,7 +380,7 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
_update_subplot_args(plt, sp, kw, idx)
|
||||
|
||||
# set default values, select from attribute cycles, and generally set the final attributes
|
||||
_add_defaults!(kw, plt, sp, i)
|
||||
_add_defaults!(kw, plt, sp, command_idx)
|
||||
|
||||
# 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,
|
||||
|
||||
122
src/recipes.jl
122
src/recipes.jl
@ -186,36 +186,7 @@ end
|
||||
# end
|
||||
|
||||
|
||||
# midpoints = d[:x]
|
||||
# heights = d[:y]
|
||||
# fillrange = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
|
||||
#
|
||||
# # estimate the edges
|
||||
# dists = diff(midpoints) * 0.5
|
||||
# edges = zeros(length(midpoints)+1)
|
||||
# for i in 1:length(edges)
|
||||
# if i == 1
|
||||
# edge = midpoints[1] - dists[1]
|
||||
# elseif i == length(edges)
|
||||
# edge = midpoints[i-1] + dists[i-2]
|
||||
# else
|
||||
# edge = midpoints[i-1] + dists[i-1]
|
||||
# end
|
||||
# edges[i] = edge
|
||||
# end
|
||||
#
|
||||
# x = Float64[]
|
||||
# y = Float64[]
|
||||
# for i in 1:length(heights)
|
||||
# e1, e2 = edges[i:i+1]
|
||||
# append!(x, [e1, e1, e2, e2])
|
||||
# append!(y, [fillrange, heights[i], heights[i], fillrange])
|
||||
# end
|
||||
#
|
||||
# d[:x] = x
|
||||
# d[:y] = y
|
||||
# d[:seriestype] = :path
|
||||
# d[:fillrange] = fillrange
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# create a bar plot as a filled step function
|
||||
@recipe function f(::Type{Val{:bar}}, x, y, z)
|
||||
@ -275,30 +246,91 @@ end
|
||||
()
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Histograms
|
||||
|
||||
# edges from number of bins
|
||||
function calc_edges(v, bins::Integer)
|
||||
vmin, vmax = extrema(v)
|
||||
linspace(vmin, vmax, bins+1)
|
||||
end
|
||||
|
||||
# just pass through arrays
|
||||
calc_edges(v, bins::AVec) = v
|
||||
|
||||
# find the bucket index of this value
|
||||
function bucket_index(vi, edges)
|
||||
for (i,e) in enumerate(edges)
|
||||
if vi <= e
|
||||
return max(1,i-1)
|
||||
end
|
||||
end
|
||||
return length(edges)-1
|
||||
end
|
||||
|
||||
function my_hist(v, bins; normed = false, weights = nothing)
|
||||
edges = calc_edges(v, bins)
|
||||
counts = zeros(length(edges)-1)
|
||||
|
||||
for (i,vi) in enumerate(v)
|
||||
idx = bucket_index(vi, edges)
|
||||
counts[idx] += (weights == nothing ? 1.0 : weights[i])
|
||||
end
|
||||
|
||||
norm_denom = normed ? sum(counts) : 1.0
|
||||
if norm_denom == 0
|
||||
norm_denom = 1.0
|
||||
end
|
||||
|
||||
edges, counts ./ norm_denom
|
||||
end
|
||||
|
||||
# # x is edges
|
||||
# for i=1:n
|
||||
# gr_fillrect(series, x[i], x[i+1], 0, y[i])
|
||||
# end
|
||||
# elseif length(x) == n
|
||||
# # x is centers
|
||||
# leftwidth = length(x) > 1 ? abs(0.5 * (x[2] - x[1])) : 0.5
|
||||
# for i=1:n
|
||||
# rightwidth = (i == n ? leftwidth : abs(0.5 * (x[i+1] - x[i])))
|
||||
# gr_fillrect(series, x[i] - leftwidth, x[i] + rightwidth, 0, y[i])
|
||||
# end
|
||||
# else
|
||||
# error("gr_barplot: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))")
|
||||
# end
|
||||
|
||||
@recipe function f(::Type{Val{:histogram}}, x, y, z)
|
||||
edges, counts = Base.hist(y, d[:bins])
|
||||
edges, counts = my_hist(y, d[:bins], normed = d[:normalize], weights = d[:weights])
|
||||
d[:x] = edges
|
||||
d[:y] = counts
|
||||
d[:seriestype] = :bar
|
||||
()
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Histogram 2D
|
||||
|
||||
# if tuple, map out bins, otherwise use the same for both
|
||||
calc_edges_2d(x, y, bins) = calc_edges(x, bins), calc_edges(y, bins)
|
||||
calc_edges_2d{X,Y}(x, y, bins::Tuple{X,Y}) = calc_edges(x, bins[1]), calc_edges(y, bins[2])
|
||||
|
||||
# the 2D version
|
||||
function my_hist_2d(x, y, bins; normed = false, weights = nothing)
|
||||
xedges, yedges = calc_edges_2d(x, y, bins)
|
||||
counts = zeros(length(yedges)-1, length(xedges)-1)
|
||||
|
||||
for i=1:length(x)
|
||||
r = bucket_index(y[i], yedges)
|
||||
c = bucket_index(x[i], xedges)
|
||||
counts[r,c] += (weights == nothing ? 1.0 : weights[i])
|
||||
end
|
||||
|
||||
norm_denom = normed ? sum(counts) : 1.0
|
||||
if norm_denom == 0
|
||||
norm_denom = 1.0
|
||||
end
|
||||
|
||||
xedges, yedges, counts ./ norm_denom
|
||||
end
|
||||
|
||||
centers(v::AVec) = v[1] + cumsum(diff(v))
|
||||
|
||||
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
|
||||
xedges, yedges, counts = my_hist_2d(x, y, d[:bins], normed = d[:normalize], weights = d[:weights])
|
||||
d[:x] = centers(xedges)
|
||||
d[:y] = centers(yedges)
|
||||
d[:z] = Surface(counts)
|
||||
d[:seriestype] = :heatmap
|
||||
()
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Box Plot
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user