series_annotations refactor and gr/pyplot fixes
This commit is contained in:
parent
af1896dc36
commit
4dfadeaf15
@ -194,7 +194,7 @@ const _series_defaults = KW(
|
|||||||
:match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
|
:match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
|
||||||
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
|
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
|
||||||
:subplot => :auto, # which subplot(s) does this series belong to?
|
:subplot => :auto, # which subplot(s) does this series belong to?
|
||||||
:series_annotations => [], # a list of annotations which apply to the coordinates of this series
|
:series_annotations => nothing, # a list of annotations which apply to the coordinates of this series
|
||||||
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
|
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
|
||||||
# one logical series to be broken up (path and markers, for example)
|
# one logical series to be broken up (path and markers, for example)
|
||||||
:hover => nothing, # text to display when hovering over the data points
|
:hover => nothing, # text to display when hovering over the data points
|
||||||
@ -440,7 +440,7 @@ add_aliases(:match_dimensions, :transpose, :transpose_z)
|
|||||||
add_aliases(:subplot, :sp, :subplt, :splt)
|
add_aliases(:subplot, :sp, :subplt, :splt)
|
||||||
add_aliases(:projection, :proj)
|
add_aliases(:projection, :proj)
|
||||||
add_aliases(:title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment)
|
add_aliases(:title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment)
|
||||||
add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation)
|
add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation, :text, :txt, :texts, :txts)
|
||||||
add_aliases(:html_output_format, :format, :fmt, :html_format)
|
add_aliases(:html_output_format, :format, :fmt, :html_format)
|
||||||
add_aliases(:orientation, :direction, :dir)
|
add_aliases(:orientation, :direction, :dir)
|
||||||
add_aliases(:inset_subplots, :inset, :floating)
|
add_aliases(:inset_subplots, :inset, :floating)
|
||||||
@ -692,6 +692,11 @@ function preprocessArgs!(d::KW)
|
|||||||
end
|
end
|
||||||
delete!(d, :fill)
|
delete!(d, :fill)
|
||||||
|
|
||||||
|
# handle series annotations
|
||||||
|
if haskey(d, :series_annotations)
|
||||||
|
d[:series_annotations] = series_annotations(wraptuple(d[:series_annotations])...)
|
||||||
|
end
|
||||||
|
|
||||||
# convert into strokes and brushes
|
# convert into strokes and brushes
|
||||||
|
|
||||||
if haskey(d, :arrow)
|
if haskey(d, :arrow)
|
||||||
|
|||||||
@ -56,8 +56,8 @@ function text_size(lablen::Int, sz::Number, rot::Number = 0)
|
|||||||
# we need to compute the size of the ticks generically
|
# we need to compute the size of the ticks generically
|
||||||
# this means computing the bounding box and then getting the width/height
|
# this means computing the bounding box and then getting the width/height
|
||||||
# note:
|
# note:
|
||||||
ptsz = 1.5sz * pt
|
ptsz = sz * pt
|
||||||
width = 0.5lablen * ptsz
|
width = 0.8lablen * ptsz
|
||||||
|
|
||||||
# now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
# now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||||
height = abs(sind(rot)) * width + abs(cosd(rot)) * ptsz
|
height = abs(sind(rot)) * width + abs(cosd(rot)) * ptsz
|
||||||
|
|||||||
@ -269,12 +269,22 @@ end
|
|||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
# draw ONE Shape
|
# draw ONE Shape
|
||||||
|
# function gr_draw_marker(xi, yi, msize, shape::Shape)
|
||||||
|
# sx, sy = shape_coords(shape)
|
||||||
|
# GR.selntran(0)
|
||||||
|
# xi, yi = GR.wctondc(xi, yi)
|
||||||
|
# GR.fillarea(xi + sx * 0.0015msize,
|
||||||
|
# yi + sy * 0.0015msize)
|
||||||
|
# GR.selntran(1)
|
||||||
|
# end
|
||||||
function gr_draw_marker(xi, yi, msize, shape::Shape)
|
function gr_draw_marker(xi, yi, msize, shape::Shape)
|
||||||
sx, sy = shape_coords(shape)
|
sx, sy = shape_coords(shape)
|
||||||
|
# convert to ndc coords (percentages of window)
|
||||||
GR.selntran(0)
|
GR.selntran(0)
|
||||||
xi, yi = GR.wctondc(xi, yi)
|
xi, yi = GR.wctondc(xi, yi)
|
||||||
GR.fillarea(xi + sx * 0.0015msize,
|
ms_ndc_x, ms_ndc_y = gr_pixels_to_ndc(msize, msize)
|
||||||
yi + sy * 0.0015msize)
|
GR.fillarea(xi .+ sx .* ms_ndc_x,
|
||||||
|
yi .+ sy .* ms_ndc_y)
|
||||||
GR.selntran(1)
|
GR.selntran(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -288,10 +298,11 @@ end
|
|||||||
|
|
||||||
# draw the markers, one at a time
|
# draw the markers, one at a time
|
||||||
function gr_draw_markers(series::Series, x, y, msize, mz)
|
function gr_draw_markers(series::Series, x, y, msize, mz)
|
||||||
shape = series[:markershape]
|
shapes = series[:markershape]
|
||||||
if shape != :none
|
if shapes != :none
|
||||||
for i=1:length(x)
|
for i=1:length(x)
|
||||||
msi = cycle(msize, i)
|
msi = cycle(msize, i)
|
||||||
|
shape = cycle(shapes, i)
|
||||||
cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor
|
cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor
|
||||||
cfuncind = isa(shape, Shape) ? GR.setfillcolorind : GR.setmarkercolorind
|
cfuncind = isa(shape, Shape) ? GR.setfillcolorind : GR.setmarkercolorind
|
||||||
|
|
||||||
@ -371,6 +382,9 @@ end
|
|||||||
# values are [xmin, xmax, ymin, ymax]. they range [0,1].
|
# values are [xmin, xmax, ymin, ymax]. they range [0,1].
|
||||||
const viewport_plotarea = zeros(4)
|
const viewport_plotarea = zeros(4)
|
||||||
|
|
||||||
|
# the size of the current plot in pixels
|
||||||
|
const gr_plot_size = zeros(2)
|
||||||
|
|
||||||
function gr_viewport_from_bbox(bb::BoundingBox, w, h, viewport_canvas)
|
function gr_viewport_from_bbox(bb::BoundingBox, w, h, viewport_canvas)
|
||||||
viewport = zeros(4)
|
viewport = zeros(4)
|
||||||
viewport[1] = viewport_canvas[2] * (left(bb) / w)
|
viewport[1] = viewport_canvas[2] * (left(bb) / w)
|
||||||
@ -425,6 +439,13 @@ gr_view_ycenter() = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4])
|
|||||||
gr_view_xdiff() = viewport_plotarea[2] - viewport_plotarea[1]
|
gr_view_xdiff() = viewport_plotarea[2] - viewport_plotarea[1]
|
||||||
gr_view_ydiff() = viewport_plotarea[4] - viewport_plotarea[3]
|
gr_view_ydiff() = viewport_plotarea[4] - viewport_plotarea[3]
|
||||||
|
|
||||||
|
function gr_pixels_to_ndc(x_pixels, y_pixels)
|
||||||
|
w,h = gr_plot_size
|
||||||
|
totx = w * gr_view_xdiff()
|
||||||
|
toty = h * gr_view_ydiff()
|
||||||
|
x_pixels / totx, y_pixels / toty
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -452,6 +473,7 @@ function gr_display(plt::Plot)
|
|||||||
# compute the viewport_canvas, normalized to the larger dimension
|
# compute the viewport_canvas, normalized to the larger dimension
|
||||||
viewport_canvas = Float64[0,1,0,1]
|
viewport_canvas = Float64[0,1,0,1]
|
||||||
w, h = plt[:size]
|
w, h = plt[:size]
|
||||||
|
gr_plot_size[:] = [w, h]
|
||||||
if w > h
|
if w > h
|
||||||
ratio = float(h) / w
|
ratio = float(h) / w
|
||||||
msize = display_width_ratio * w
|
msize = display_width_ratio * w
|
||||||
@ -737,6 +759,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
x, y, z = series[:x], series[:y], series[:z]
|
x, y, z = series[:x], series[:y], series[:z]
|
||||||
frng = series[:fillrange]
|
frng = series[:fillrange]
|
||||||
|
|
||||||
|
# add custom frame shapes to markershape?
|
||||||
|
series_annotations_shapes!(series)
|
||||||
|
# -------------------------------------------------------
|
||||||
|
|
||||||
# recompute data
|
# recompute data
|
||||||
if typeof(z) <: Surface
|
if typeof(z) <: Surface
|
||||||
# if st == :heatmap
|
# if st == :heatmap
|
||||||
@ -937,6 +963,53 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# if anns != nothing
|
||||||
|
# TODO handle series annotations
|
||||||
|
# TODO: this should be moved with SeriesAnnotations... iterate like:
|
||||||
|
# for (xi,yi,str,shape) in eachann(anns, sp) ... end
|
||||||
|
# or maybe
|
||||||
|
# anns.sp = sp
|
||||||
|
# for (xi,yi,str,shape) in anns ... end
|
||||||
|
# TODO: maybe scrap all of this and do some preprocessing to overwrite the marker shape with
|
||||||
|
# a vector of the computed shapes?? then marker_z, etc will still work
|
||||||
|
# @assert !is3d(sp)
|
||||||
|
# shapefillcolor = plot_color(ann.shapefill.color, ann.shapefill.alpha)
|
||||||
|
# shapestrokecolor = plot_color(ann.shapestroke.color, ann.shapestroke.alpha)
|
||||||
|
# for i=1:length(y)
|
||||||
|
# xi = cycle(x,i)
|
||||||
|
# yi = cycle(y,i)
|
||||||
|
# # @show anns.strs typeof(anns.strs)
|
||||||
|
# str = cycle(anns.strs,i)
|
||||||
|
|
||||||
|
# if !isnull(anns.baseshape)
|
||||||
|
# # get the width and height of the string (in mm)
|
||||||
|
# sw, sh = text_size(str, anns.font.pointsize)
|
||||||
|
#
|
||||||
|
# # how much to scale the base shape?
|
||||||
|
# xscale = 0.5 * resolve_mixed(MixedMeasures(0, 0, sw), sp, :x)
|
||||||
|
# yscale = 0.5 * resolve_mixed(MixedMeasures(0, 0, sh), sp, :y)
|
||||||
|
#
|
||||||
|
# # get the shape for this x/y/str
|
||||||
|
# shape = scale(get(anns.baseshape), xscale, yscale)
|
||||||
|
# translate!(shape, xi, yi)
|
||||||
|
#
|
||||||
|
# # draw the interior
|
||||||
|
# gr_set_fill(shapefillcolor)
|
||||||
|
# GR.fillarea(shape_coords(shape)...)
|
||||||
|
#
|
||||||
|
# # draw the shapes
|
||||||
|
# gr_set_line(anns.shapestroke.width, anns.shapestroke.style, shapestrokecolor)
|
||||||
|
# GR.polyline(shape_coords(shape)...)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# this is all we need to add the series_annotations text
|
||||||
|
anns = series[:series_annotations]
|
||||||
|
for (xi,yi,str) in EachAnn(anns, x, y)
|
||||||
|
gr_set_font(anns.font)
|
||||||
|
gr_text(GR.wctondc(xi, yi)..., str)
|
||||||
|
end
|
||||||
|
# end
|
||||||
|
|
||||||
GR.restorestate()
|
GR.restorestate()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1021,55 +1094,14 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
for ann in sp[:annotations]
|
for ann in sp[:annotations]
|
||||||
if isa(ann, SeriesAnnotations)
|
x, y, val = ann
|
||||||
# TODO handle series annotations
|
x, y = if is3d(sp)
|
||||||
# TODO: this should be moved with SeriesAnnotations... iterate like:
|
# GR.wc3towc(x, y, z)
|
||||||
# for (xi,yi,str,shape) in eachann(anns, sp) ... end
|
|
||||||
# or maybe
|
|
||||||
# anns.sp = sp
|
|
||||||
# for (xi,yi,str,shape) in anns ... end
|
|
||||||
@assert !is3d(sp)
|
|
||||||
shapefillcolor = plot_color(ann.shapefill.color, ann.shapefill.alpha)
|
|
||||||
shapestrokecolor = plot_color(ann.shapestroke.color, ann.shapestroke.alpha)
|
|
||||||
for i=1:length(ann.y)
|
|
||||||
xi = cycle(ann.x,i)
|
|
||||||
yi = cycle(ann.y,i)
|
|
||||||
str = cycle(ann.strs,i)
|
|
||||||
|
|
||||||
if !isnull(ann.baseshape)
|
|
||||||
# get the width and height of the string (in mm)
|
|
||||||
sw, sh = text_size(str, ann.font.pointsize)
|
|
||||||
|
|
||||||
# how much to scale the base shape?
|
|
||||||
xscale = 0.5 * resolve_mixed(MixedMeasures(0, 0, sw), sp, :x)
|
|
||||||
yscale = 0.5 * resolve_mixed(MixedMeasures(0, 0, sh), sp, :y)
|
|
||||||
|
|
||||||
# get the shape for this x/y/str
|
|
||||||
shape = scale(get(ann.baseshape), xscale, yscale)
|
|
||||||
translate!(shape, xi, yi)
|
|
||||||
|
|
||||||
# draw the interior
|
|
||||||
gr_set_fill(shapefillcolor)
|
|
||||||
GR.fillarea(shape_coords(shape)...)
|
|
||||||
|
|
||||||
# draw the shapes
|
|
||||||
gr_set_line(ann.shapestroke.width, ann.shapestroke.style, shapestrokecolor)
|
|
||||||
GR.polyline(shape_coords(shape)...)
|
|
||||||
end
|
|
||||||
|
|
||||||
gr_set_font(ann.font)
|
|
||||||
gr_text(GR.wctondc(xi, yi)..., str)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
x, y, val = ann
|
GR.wctondc(x, y)
|
||||||
x, y = if is3d(sp)
|
|
||||||
# GR.wc3towc(x, y, z)
|
|
||||||
else
|
|
||||||
GR.wctondc(x, y)
|
|
||||||
end
|
|
||||||
gr_set_font(val.font)
|
|
||||||
gr_text(x, y, val.str)
|
|
||||||
end
|
end
|
||||||
|
gr_set_font(val.font)
|
||||||
|
gr_text(x, y, val.str)
|
||||||
end
|
end
|
||||||
GR.restorestate()
|
GR.restorestate()
|
||||||
end
|
end
|
||||||
|
|||||||
@ -445,6 +445,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
|||||||
error("Only numbers and vectors are supported with levels keyword")
|
error("Only numbers and vectors are supported with levels keyword")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# add custom frame shapes to markershape?
|
||||||
|
series_annotations_shapes!(series, :xy)
|
||||||
|
|
||||||
# for each plotting command, optionally build and add a series handle to the list
|
# for each plotting command, optionally build and add a series handle to the list
|
||||||
|
|
||||||
# line plot
|
# line plot
|
||||||
@ -560,16 +563,46 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
|||||||
else
|
else
|
||||||
xyargs
|
xyargs
|
||||||
end
|
end
|
||||||
handle = ax[:scatter](xyargs...;
|
|
||||||
label = series[:label],
|
if isa(series[:markershape], AbstractVector{Shape})
|
||||||
zorder = series[:series_plotindex] + 0.5,
|
# this section will create one scatter per data point to accomodate the
|
||||||
marker = py_marker(series[:markershape]),
|
# vector of shapes
|
||||||
s = py_dpi_scale(plt, series[:markersize] .^ 2),
|
handle = []
|
||||||
edgecolors = py_markerstrokecolor(series),
|
x,y = xyargs
|
||||||
linewidths = py_dpi_scale(plt, series[:markerstrokewidth]),
|
shapes = series[:markershape]
|
||||||
extrakw...
|
msc = py_markerstrokecolor(series)
|
||||||
)
|
lw = py_dpi_scale(plt, series[:markerstrokewidth])
|
||||||
push!(handles, handle)
|
for i=1:length(y)
|
||||||
|
extrakw[:c] = if series[:marker_z] == nothing
|
||||||
|
py_color_fix(py_color(cycle(series[:markercolor],i)), x)
|
||||||
|
else
|
||||||
|
extrakw[:c]
|
||||||
|
end
|
||||||
|
|
||||||
|
push!(handle, ax[:scatter](cycle(x,i), cycle(y,i);
|
||||||
|
label = series[:label],
|
||||||
|
zorder = series[:series_plotindex] + 0.5,
|
||||||
|
marker = py_marker(cycle(shapes,i)),
|
||||||
|
s = py_dpi_scale(plt, cycle(series[:markersize],i) .^ 2),
|
||||||
|
edgecolors = msc,
|
||||||
|
linewidths = lw,
|
||||||
|
extrakw...
|
||||||
|
))
|
||||||
|
end
|
||||||
|
push!(handles, handle)
|
||||||
|
else
|
||||||
|
# do a normal scatter plot
|
||||||
|
handle = ax[:scatter](xyargs...;
|
||||||
|
label = series[:label],
|
||||||
|
zorder = series[:series_plotindex] + 0.5,
|
||||||
|
marker = py_marker(series[:markershape]),
|
||||||
|
s = py_dpi_scale(plt, series[:markersize] .^ 2),
|
||||||
|
edgecolors = py_markerstrokecolor(series),
|
||||||
|
linewidths = py_dpi_scale(plt, series[:markerstrokewidth]),
|
||||||
|
extrakw...
|
||||||
|
)
|
||||||
|
push!(handles, handle)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if st == :hexbin
|
if st == :hexbin
|
||||||
@ -849,6 +882,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
|||||||
)
|
)
|
||||||
push!(handles, handle)
|
push!(handles, handle)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# this is all we need to add the series_annotations text
|
||||||
|
anns = series[:series_annotations]
|
||||||
|
for (xi,yi,str) in EachAnn(anns, x, y)
|
||||||
|
py_add_annotations(sp, xi, yi, PlotText(str, anns.font))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|||||||
@ -23,6 +23,7 @@ immutable Shape
|
|||||||
# end
|
# end
|
||||||
end
|
end
|
||||||
Shape(verts::AVec) = Shape(unzip(verts)...)
|
Shape(verts::AVec) = Shape(unzip(verts)...)
|
||||||
|
Shape(s::Shape) = deepcopy(s)
|
||||||
|
|
||||||
get_xs(shape::Shape) = shape.x
|
get_xs(shape::Shape) = shape.x
|
||||||
get_ys(shape::Shape) = shape.y
|
get_ys(shape::Shape) = shape.y
|
||||||
@ -143,6 +144,8 @@ for n in [4,5,6,7,8]
|
|||||||
_shapes[Symbol("star$n")] = makestar(n)
|
_shapes[Symbol("star$n")] = makestar(n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Shape(k::Symbol) = deepcopy(_shapes[k])
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@ -307,7 +310,7 @@ function text(str, args...)
|
|||||||
PlotText(string(str), font(args...))
|
PlotText(string(str), font(args...))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Base.length(t::PlotText) = length(t.str)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -386,44 +389,104 @@ end
|
|||||||
type SeriesAnnotations
|
type SeriesAnnotations
|
||||||
strs::AbstractVector # the labels/names
|
strs::AbstractVector # the labels/names
|
||||||
font::Font
|
font::Font
|
||||||
baseshape::Nullable{Shape}
|
baseshape::Nullable
|
||||||
shapefill::Brush
|
# shapefill::Brush
|
||||||
shapestroke::Stroke
|
# shapestroke::Stroke
|
||||||
x
|
# x
|
||||||
y
|
# y
|
||||||
end
|
end
|
||||||
function series_annotations(strs::AbstractVector, args...)
|
function series_annotations(strs::AbstractVector, args...)
|
||||||
fnt = font()
|
fnt = font()
|
||||||
shp = Nullable{Shape}()
|
shp = Nullable{Any}()
|
||||||
br = brush(:steelblue)
|
scalefactor = 1
|
||||||
stk = stroke()
|
# br = brush(:steelblue)
|
||||||
α = nothing
|
# stk = stroke()
|
||||||
|
# α = nothing
|
||||||
for arg in args
|
for arg in args
|
||||||
if isa(arg, Shape)
|
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
|
||||||
shp = Nullable{Shape}(arg)
|
shp = Nullable(arg)
|
||||||
elseif isa(arg, Brush)
|
# elseif isa(arg, Brush)
|
||||||
brush = arg
|
# brush = arg
|
||||||
elseif isa(arg, Stroke)
|
# elseif isa(arg, Stroke)
|
||||||
stk = arg
|
# stk = arg
|
||||||
elseif isa(arg, Font)
|
elseif isa(arg, Font)
|
||||||
fnt = arg
|
fnt = arg
|
||||||
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
||||||
shp = _shapes[arg]
|
shp = _shapes[arg]
|
||||||
elseif allAlphas(arg)
|
# elseif allAlphas(arg)
|
||||||
α = arg
|
# α = arg
|
||||||
|
elseif isa(arg, Number)
|
||||||
|
scalefactor = arg
|
||||||
else
|
else
|
||||||
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if α != nothing
|
if scalefactor != 1
|
||||||
br.alpha = α
|
for s in get(shp)
|
||||||
stk.alpha = α
|
scale!(s, scalefactor, scalefactor, (0,0))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
# if α != nothing
|
||||||
|
# br.alpha = α
|
||||||
|
# stk.alpha = α
|
||||||
|
# end
|
||||||
# note: x/y coords are added later
|
# note: x/y coords are added later
|
||||||
SeriesAnnotations(strs, fnt, shp, br, stk, nothing, nothing)
|
SeriesAnnotations(strs, fnt, shp)
|
||||||
|
end
|
||||||
|
series_annotations(anns::SeriesAnnotations) = anns
|
||||||
|
series_annotations(::Void) = nothing
|
||||||
|
|
||||||
|
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||||
|
anns = series[:series_annotations]
|
||||||
|
if anns != nothing && !isnull(anns.baseshape)
|
||||||
|
# x = series[:x]
|
||||||
|
# y = series[:y]
|
||||||
|
# we should use baseshape to overwrite the markershape attribute
|
||||||
|
# with a list of custom shapes for each
|
||||||
|
msize = Float64[]
|
||||||
|
shapes = Shape[begin
|
||||||
|
# xi = cycle(x,i)
|
||||||
|
# yi = cycle(y,i)
|
||||||
|
str = cycle(anns.strs,i)
|
||||||
|
|
||||||
|
# get the width and height of the string (in mm)
|
||||||
|
sw, sh = text_size(str, anns.font.pointsize)
|
||||||
|
|
||||||
|
# how much to scale the base shape?
|
||||||
|
# note: it's a rough assumption that the shape fills the unit box [-1,-1,1,1],
|
||||||
|
# so we scale the length-2 shape by 1/2 the total length
|
||||||
|
# if scaletype == :pixels
|
||||||
|
scalar = (backend() == PyPlotBackend() ? 1.7 : 1.0)
|
||||||
|
xscale = 0.5to_pixels(sw) * scalar
|
||||||
|
yscale = 0.55to_pixels(sh) * scalar
|
||||||
|
# else
|
||||||
|
# sp = series[:subplot]
|
||||||
|
# xscale = 0.5 * resolve_mixed(MixedMeasures(0, 0, sw), sp, :x)
|
||||||
|
# yscale = 0.5 * resolve_mixed(MixedMeasures(0, 0, sh), sp, :y)
|
||||||
|
# end
|
||||||
|
maxscale = max(xscale, yscale)
|
||||||
|
push!(msize, maxscale)
|
||||||
|
|
||||||
|
# get the shape for this x/y/str
|
||||||
|
# @show get(anns.baseshape) xscale,yscale
|
||||||
|
baseshape = cycle(get(anns.baseshape),i)
|
||||||
|
shape = scale(baseshape, xscale/maxscale, yscale/maxscale, (0,0))
|
||||||
|
# @show shape
|
||||||
|
end for i=1:length(anns.strs)]
|
||||||
|
series[:markershape] = shapes
|
||||||
|
series[:markersize] = msize #1 # the scaling is handled in the shapes
|
||||||
|
end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
type EachAnn
|
||||||
|
anns
|
||||||
|
x
|
||||||
|
y
|
||||||
|
end
|
||||||
|
Base.start(ea::EachAnn) = 1
|
||||||
|
Base.done(ea::EachAnn, i) = ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
|
||||||
|
Base.next(ea::EachAnn, i) = ((cycle(ea.x,i), cycle(ea.y,i), cycle(ea.anns.strs,i)), i+1)
|
||||||
|
|
||||||
annotations(::Void) = []
|
annotations(::Void) = []
|
||||||
annotations(anns::AVec) = anns
|
annotations(anns::AVec) = anns
|
||||||
|
|||||||
@ -111,6 +111,7 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
|
|||||||
if mix.len != 0mm
|
if mix.len != 0mm
|
||||||
f = (letter == :x ? width : height)
|
f = (letter == :x ? width : height)
|
||||||
totlen = f(plotarea(sp))
|
totlen = f(plotarea(sp))
|
||||||
|
@show totlen
|
||||||
pct += mix.len / totlen
|
pct += mix.len / totlen
|
||||||
end
|
end
|
||||||
if pct != 0
|
if pct != 0
|
||||||
|
|||||||
@ -333,17 +333,17 @@ function _prepare_annotations(sp::Subplot, d::KW)
|
|||||||
# strip out series annotations (those which are based on series x/y coords)
|
# strip out series annotations (those which are based on series x/y coords)
|
||||||
# and add them to the subplot attr
|
# and add them to the subplot attr
|
||||||
sp_anns = annotations(sp[:annotations])
|
sp_anns = annotations(sp[:annotations])
|
||||||
series_anns = annotations(pop!(d, :series_annotations, []))
|
# series_anns = annotations(pop!(d, :series_annotations, []))
|
||||||
if isa(series_anns, SeriesAnnotations)
|
# if isa(series_anns, SeriesAnnotations)
|
||||||
series_anns.x = d[:x]
|
# series_anns.x = d[:x]
|
||||||
series_anns.y = d[:y]
|
# series_anns.y = d[:y]
|
||||||
elseif length(series_anns) > 0
|
# elseif length(series_anns) > 0
|
||||||
x, y = d[:x], d[:y]
|
# x, y = d[:x], d[:y]
|
||||||
nx, ny, na = map(length, (x,y,series_anns))
|
# nx, ny, na = map(length, (x,y,series_anns))
|
||||||
n = max(nx, ny, na)
|
# n = max(nx, ny, na)
|
||||||
series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
|
# series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
|
||||||
end
|
# end
|
||||||
sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
||||||
end
|
end
|
||||||
|
|
||||||
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user