axes log scales, colors, ticks, and more; proper 2D axis drawing in GR
This commit is contained in:
parent
ee706ad8c7
commit
a0ac70be3c
106
src/axes.jl
106
src/axes.jl
@ -117,17 +117,77 @@ Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.d, v, ks...)
|
|||||||
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.d, k)
|
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.d, k)
|
||||||
Base.extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
|
Base.extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
|
||||||
|
|
||||||
|
|
||||||
|
const _scale_funcs = Dict{Symbol,Function}(
|
||||||
|
:log10 => log10,
|
||||||
|
:log2 => log2,
|
||||||
|
:ln => log,
|
||||||
|
)
|
||||||
|
const _inv_scale_funcs = Dict{Symbol,Function}(
|
||||||
|
:log10 => exp10,
|
||||||
|
:log2 => exp2,
|
||||||
|
:ln => exp,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
scalefunc(scale::Symbol) = get(_scale_funcs, scale, identity)
|
||||||
|
invscalefunc(scale::Symbol) = get(_inv_scale_funcs, scale, identity)
|
||||||
|
|
||||||
|
function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
|
||||||
|
lims = axis_limits(axis)
|
||||||
|
|
||||||
|
# scale the limits
|
||||||
|
scale = axis[:scale]
|
||||||
|
scaled_lims = map(scalefunc(scale), lims)
|
||||||
|
# scaled_lims = if scale == :log10 # TODO: log10(xmin), log10(xmax)
|
||||||
|
# map(log10, lims)
|
||||||
|
# elseif scale == :log2
|
||||||
|
# map(log2, lims)
|
||||||
|
# elseif scale == :ln
|
||||||
|
# map(log, lims)
|
||||||
|
# else
|
||||||
|
# lims
|
||||||
|
# end
|
||||||
|
|
||||||
|
# get a list of well-laid-out ticks
|
||||||
|
cv = if ticks == nothing
|
||||||
|
optimize_ticks(scaled_lims...)[1]
|
||||||
|
else
|
||||||
|
ticks
|
||||||
|
end
|
||||||
|
|
||||||
|
# rescale and return values and labels
|
||||||
|
tickvals = map(invscalefunc(scale), cv)
|
||||||
|
basestr = scale == :log10 ? "10^" : scale == :log2 ? "2^" : scale == :ln ? "e^" : ""
|
||||||
|
tickvals, ["$basestr$cvi" for cvi in cv]
|
||||||
|
# if scale == :log10
|
||||||
|
# map(exp10, cv), ["10^$cvi" for cvi in cv]
|
||||||
|
# elseif scale == :log2
|
||||||
|
# map(exp2, cv), ["2^$cvi" for cvi in cv]
|
||||||
|
# elseif scale == :ln
|
||||||
|
# map(exp, cv), ["e^$cvi" for cvi in cv]
|
||||||
|
# else
|
||||||
|
# cv, map(string, cv)
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
||||||
# return (continuous_values, discrete_values) for the ticks on this axis
|
# return (continuous_values, discrete_values) for the ticks on this axis
|
||||||
function get_ticks(axis::Axis)
|
function get_ticks(axis::Axis)
|
||||||
ticks = axis[:ticks]
|
ticks = axis[:ticks]
|
||||||
|
ticks in (nothing, false) && return nothing
|
||||||
|
|
||||||
dvals = axis[:discrete_values]
|
dvals = axis[:discrete_values]
|
||||||
cv, dv = if !isempty(dvals) && ticks == :auto
|
cv, dv = if !isempty(dvals) && ticks == :auto
|
||||||
# discrete ticks...
|
# discrete ticks...
|
||||||
axis[:continuous_values], dvals
|
axis[:continuous_values], dvals
|
||||||
elseif ticks == :auto
|
elseif ticks == :auto
|
||||||
cv = optimize_ticks(map(Float64, axis_limits(axis))..., k_max=5)[1]
|
# compute optimal ticks and labels
|
||||||
cv, cv
|
optimal_ticks_and_labels(axis)
|
||||||
|
elseif typeof(ticks) <: AVec
|
||||||
|
# override ticks, but get the labels
|
||||||
|
optimal_ticks_and_labels(axis, ticks)
|
||||||
elseif typeof(ticks) <: NTuple{2}
|
elseif typeof(ticks) <: NTuple{2}
|
||||||
|
# assuming we're passed (ticks, labels)
|
||||||
ticks
|
ticks
|
||||||
else
|
else
|
||||||
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
|
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
|
||||||
@ -360,24 +420,34 @@ function axis_drawing_info(sp::Subplot)
|
|||||||
spine_segs = Segments(2)
|
spine_segs = Segments(2)
|
||||||
grid_segs = Segments(2)
|
grid_segs = Segments(2)
|
||||||
|
|
||||||
# x axis
|
if !(xaxis[:ticks] in (nothing, false))
|
||||||
ticksz = 0.015 * (ymax - ymin)
|
f = scalefunc(yaxis[:scale])
|
||||||
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
|
invf = invscalefunc(yaxis[:scale])
|
||||||
push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
|
t1 = invf(f(ymin) + 0.015*(f(ymax)-f(ymin)))
|
||||||
for xtick in xticks[1]
|
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin)))
|
||||||
push!(spine_segs, (xtick, ymin), (xtick, ymin+ticksz)) # bottom tick
|
|
||||||
push!(grid_segs, (xtick, ymin+ticksz), (xtick, ymax-ticksz)) # vertical grid
|
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
|
||||||
push!(spine_segs, (xtick, ymax), (xtick, ymax-ticksz)) # top tick
|
push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
|
||||||
|
for xtick in xticks[1]
|
||||||
|
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
|
||||||
|
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid
|
||||||
|
push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# y axis
|
if !(yaxis[:ticks] in (nothing, false))
|
||||||
ticksz = 0.015 * (xmax - xmin)
|
f = scalefunc(xaxis[:scale])
|
||||||
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
|
invf = invscalefunc(xaxis[:scale])
|
||||||
push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
|
t1 = invf(f(xmin) + 0.015*(f(xmax)-f(xmin)))
|
||||||
for ytick in yticks[1]
|
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
|
||||||
push!(spine_segs, (xmin, ytick), (xmin+ticksz, ytick)) # left tick
|
|
||||||
push!(grid_segs, (xmin+ticksz, ytick), (xmax-ticksz, ytick)) # horizontal grid
|
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
|
||||||
push!(spine_segs, (xmax, ytick), (xmax-ticksz, ytick)) # right tick
|
push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
|
||||||
|
for ytick in yticks[1]
|
||||||
|
push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick
|
||||||
|
push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
|
||||||
|
push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
xticks, yticks, spine_segs, grid_segs
|
xticks, yticks, spine_segs, grid_segs
|
||||||
|
|||||||
@ -328,14 +328,14 @@ end
|
|||||||
const _gr_point_mult = zeros(1)
|
const _gr_point_mult = zeros(1)
|
||||||
|
|
||||||
# set the font attributes... assumes _gr_point_mult has been populated already
|
# set the font attributes... assumes _gr_point_mult has been populated already
|
||||||
function gr_set_font(f::Font; halign = f.halign, valign = f.valign)
|
function gr_set_font(f::Font; halign = f.halign, valign = f.valign, color = f.color)
|
||||||
family = lowercase(f.family)
|
family = lowercase(f.family)
|
||||||
GR.setcharheight(_gr_point_mult[1] * f.pointsize)
|
GR.setcharheight(_gr_point_mult[1] * f.pointsize)
|
||||||
GR.setcharup(sin(f.rotation), cos(f.rotation))
|
GR.setcharup(sin(f.rotation), cos(f.rotation))
|
||||||
if haskey(gr_font_family, family)
|
if haskey(gr_font_family, family)
|
||||||
GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING)
|
GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING)
|
||||||
end
|
end
|
||||||
gr_set_textcolor(f.color)
|
gr_set_textcolor(color)
|
||||||
GR.settextalign(gr_halign[halign], gr_valign[valign])
|
GR.settextalign(gr_halign[halign], gr_valign[valign])
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -582,20 +582,26 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
|
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
|
||||||
gr_polyline(coords(spine_segs)...)
|
gr_polyline(coords(spine_segs)...)
|
||||||
|
|
||||||
# x labels
|
if !(xticks in (nothing, false))
|
||||||
gr_set_font(sp[:xaxis][:tickfont], valign = :top)
|
# x labels
|
||||||
for (cv, dv) in zip(xticks...)
|
flip = sp[:yaxis][:flip]
|
||||||
xi, yi = GR.wctondc(cv, ymin)
|
gr_set_font(sp[:xaxis][:tickfont], valign = :top, color = sp[:xaxis][:foreground_color_axis])
|
||||||
# @show cv dv ymin xi yi
|
for (cv, dv) in zip(xticks...)
|
||||||
gr_text(xi, yi-0.01, string(dv))
|
xi, yi = GR.wctondc(cv, flip ? ymax : ymin)
|
||||||
|
# @show cv dv ymin xi yi
|
||||||
|
gr_text(xi, yi-0.01, string(dv))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# y labels
|
if !(yticks in (nothing, false))
|
||||||
gr_set_font(sp[:yaxis][:tickfont], halign = :right)
|
# y labels
|
||||||
for (cv, dv) in zip(yticks...)
|
flip = sp[:xaxis][:flip]
|
||||||
xi, yi = GR.wctondc(xmin, cv)
|
gr_set_font(sp[:yaxis][:tickfont], halign = :right, color = sp[:yaxis][:foreground_color_axis])
|
||||||
# @show cv dv xmin xi yi
|
for (cv, dv) in zip(yticks...)
|
||||||
gr_text(xi-0.01, yi, string(dv))
|
xi, yi = GR.wctondc(flip ? xmax : xmin, cv)
|
||||||
|
# @show cv dv xmin xi yi
|
||||||
|
gr_text(xi-0.01, yi, string(dv))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# window_diag = sqrt(gr_view_xdiff()^2 + gr_view_ydiff()^2)
|
# window_diag = sqrt(gr_view_xdiff()^2 + gr_view_ydiff()^2)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user