axis_drawing_info and get_ticks; parameterized Segments; GR manual drawing of 2D axes

This commit is contained in:
Thomas Breloff 2016-07-13 16:31:21 -04:00
parent dcab8e3ac2
commit ee706ad8c7
4 changed files with 128 additions and 47 deletions

View File

@ -81,16 +81,6 @@ export
arrow, arrow,
Segments, Segments,
# colorscheme,
# ColorScheme,
# ColorGradient,
# ColorVector,
# ColorWrapper,
# ColorFunction,
# ColorZFunction,
# getColor,
# getColorZ,
debugplots, debugplots,
supported_args, supported_args,
@ -109,6 +99,7 @@ export
test_examples, test_examples,
iter_segments, iter_segments,
coords,
translate, translate,
translate!, translate!,

View File

@ -117,21 +117,29 @@ 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))
# get discrete ticks, or not # 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]
dvals = axis[:discrete_values] dvals = axis[:discrete_values]
if !isempty(dvals) && ticks == :auto cv, dv = if !isempty(dvals) && ticks == :auto
cv, dv = axis[:continuous_values], dvals # discrete ticks...
# TODO: better/smarter cutoff values for sampling ticks axis[:continuous_values], dvals
if length(cv) > 30 elseif ticks == :auto
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)] cv = optimize_ticks(map(Float64, axis_limits(axis))..., k_max=5)[1]
cv[rng], dv[rng] cv, cv
else elseif typeof(ticks) <: NTuple{2}
cv, dv
end
else
ticks ticks
else
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
end
# @show ticks dvals cv dv
# TODO: better/smarter cutoff values for sampling ticks
if length(cv) > 30
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)]
cv[rng], dv[rng]
else
cv, dv
end end
end end
@ -339,3 +347,39 @@ function pie_labels(sp::Subplot, series::Series)
d[:x] d[:x]
end end
end end
# -------------------------------------------------------------------------
# compute the line segments which should be drawn for this axis
function axis_drawing_info(sp::Subplot)
xaxis, yaxis = sp[:xaxis], sp[:yaxis]
xmin, xmax = axis_limits(xaxis)
ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
spine_segs = Segments(2)
grid_segs = Segments(2)
# x axis
ticksz = 0.015 * (ymax - ymin)
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
for xtick in xticks[1]
push!(spine_segs, (xtick, ymin), (xtick, ymin+ticksz)) # bottom tick
push!(grid_segs, (xtick, ymin+ticksz), (xtick, ymax-ticksz)) # vertical grid
push!(spine_segs, (xtick, ymax), (xtick, ymax-ticksz)) # top tick
end
# y axis
ticksz = 0.015 * (xmax - xmin)
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
for ytick in yticks[1]
push!(spine_segs, (xmin, ytick), (xmin+ticksz, ytick)) # left tick
push!(grid_segs, (xmin+ticksz, ytick), (xmax-ticksz, ytick)) # horizontal grid
push!(spine_segs, (xmax, ytick), (xmax-ticksz, ytick)) # right tick
end
xticks, yticks, spine_segs, grid_segs
end

View File

@ -328,7 +328,7 @@ 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) function gr_set_font(f::Font; halign = f.halign, valign = f.valign)
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))
@ -336,7 +336,7 @@ function gr_set_font(f::Font)
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(f.color)
GR.settextalign(gr_halign[f.halign], gr_valign[f.valign]) GR.settextalign(gr_halign[halign], gr_valign[valign])
end end
# -------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------
@ -448,7 +448,7 @@ function gr_display(plt::Plot)
# update point mult # update point mult
px_per_pt = px / pt px_per_pt = px / pt
_gr_point_mult[1] = px_per_pt / h _gr_point_mult[1] = px_per_pt / max(h,w)
# subplots: # subplots:
for sp in plt.subplots for sp in plt.subplots
@ -561,26 +561,55 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_polaraxes(rmin, rmax) gr_polaraxes(rmin, rmax)
elseif draw_axes elseif draw_axes
if xmax > xmin && ymax > ymin
GR.setwindow(xmin, xmax, ymin, ymax)
end
xticks, yticks, spine_segs, grid_segs = axis_drawing_info(sp)
# @show xticks yticks spine_segs grid_segs
# draw the grid lines # draw the grid lines
# TODO: control line style/width
# GR.setlinetype(GR.LINETYPE_DOTTED)
if sp[:grid] if sp[:grid]
gr_set_linecolor(sp[:foreground_color_grid]) # gr_set_linecolor(sp[:foreground_color_grid])
GR.grid(xtick, ytick, 0, 0, majorx, majory) # GR.grid(xtick, ytick, 0, 0, majorx, majory)
gr_set_line(1, :dot, sp[:foreground_color_grid])
GR.settransparency(0.5)
gr_polyline(coords(grid_segs)...)
end
GR.settransparency(1.0)
# spine (border) and tick marks
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
gr_polyline(coords(spine_segs)...)
# x labels
gr_set_font(sp[:xaxis][:tickfont], valign = :top)
for (cv, dv) in zip(xticks...)
xi, yi = GR.wctondc(cv, ymin)
# @show cv dv ymin xi yi
gr_text(xi, yi-0.01, string(dv))
end end
window_diag = sqrt(gr_view_xdiff()^2 + gr_view_ydiff()^2) # y labels
ticksize = 0.0075 * window_diag gr_set_font(sp[:yaxis][:tickfont], halign = :right)
if outside_ticks for (cv, dv) in zip(yticks...)
ticksize = -ticksize xi, yi = GR.wctondc(xmin, cv)
# @show cv dv xmin xi yi
gr_text(xi-0.01, yi, string(dv))
end end
# TODO: this should be done for each axis separately
gr_set_linecolor(xaxis[:foreground_color_axis])
x1, x2 = xaxis[:flip] ? (xmax,xmin) : (xmin,xmax) # window_diag = sqrt(gr_view_xdiff()^2 + gr_view_ydiff()^2)
y1, y2 = yaxis[:flip] ? (ymax,ymin) : (ymin,ymax) # ticksize = 0.0075 * window_diag
GR.axes(xtick, ytick, x1, y1, 1, 1, ticksize) # if outside_ticks
GR.axes(xtick, ytick, x2, y2, -1, -1, -ticksize) # ticksize = -ticksize
# end
# # TODO: this should be done for each axis separately
# gr_set_linecolor(xaxis[:foreground_color_axis])
# x1, x2 = xaxis[:flip] ? (xmax,xmin) : (xmin,xmax)
# y1, y2 = yaxis[:flip] ? (ymax,ymin) : (ymin,ymax)
# GR.axes(xtick, ytick, x1, y1, 1, 1, ticksize)
# GR.axes(xtick, ytick, x2, y2, -1, -1, -ticksize)
end end
# end # end

View File

@ -138,24 +138,41 @@ end
# --------------------------------------------------------------- # ---------------------------------------------------------------
type Segments type Segments{T}
pts::Vector{Float64} pts::Vector{T}
end end
Segments() = Segments(zeros(0)) # Segments() = Segments{Float64}(zeros(0))
function Base.push!(segments::Segments, vs...) Segments() = Segments(Float64)
push!(segments.pts, NaN) Segments{T}(::Type{T}) = Segments(T[])
Segments(p::Int) = Segments(NTuple{2,Float64}[])
# Segments() = Segments(zeros(0))
to_nan(::Type{Float64}) = NaN
to_nan(::Type{NTuple{2,Float64}}) = (NaN, NaN)
coords(segs::Segments{Float64}) = segs.pts
coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts]
function Base.push!{T}(segments::Segments{T}, vs...)
if !isempty(segments.pts)
push!(segments.pts, to_nan(T))
end
for v in vs for v in vs
push!(segments.pts, v) push!(segments.pts, convert(T,v))
end end
segments segments
end end
function Base.push!(segments::Segments, vs::AVec) function Base.push!{T}(segments::Segments{T}, vs::AVec)
push!(segments.pts, NaN) if !isempty(segments.pts)
push!(segments.pts, to_nan(T))
end
for v in vs for v in vs
push!(segments.pts, v) push!(segments.pts, convert(T,v))
end end
segments segments
end end