Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 824d502c37 | |||
| 36ff017c4f | |||
| 3ef9fe142c | |||
| 4bf0c496d8 | |||
| 9bf4bda852 | |||
| fa7f10a6e9 | |||
| 483e45db8a | |||
| e6097f4534 | |||
| 749f56084a | |||
| 2fa4a63f02 | |||
| 9b1249abce | |||
| bbfc0bc77a | |||
| 5a416e51d2 | |||
| 67ba06cd77 | |||
| aa61d681d9 | |||
| c8e6b967e5 | |||
| 819e91aa37 | |||
| 7f835cf7cb | |||
| 43571e6d40 | |||
| dd3666b6d3 | |||
| f98b191616 | |||
| 9fdcf0db74 | |||
| 7abab41f2b | |||
| 45569c0d4d | |||
| ca653c5bec | |||
| 6c0539bac6 | |||
| 65c9a46c8d | |||
| 7bd97558dc | |||
| 6807f53a7e | |||
| ae396ef576 | |||
| 3dd1c500cf | |||
| 59e4129194 | |||
| 54d441b62a | |||
| f8d36363b4 | |||
| c32c7fda58 | |||
| 87b220e747 | |||
| 57a6f4303b | |||
| 407456eac5 | |||
| f118d0cd35 | |||
| 1b0fb95583 | |||
| 0daed24020 | |||
| dc5ae4ef96 |
+2
-2
@@ -1,7 +1,7 @@
|
||||
name = "Plots"
|
||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
author = ["Tom Breloff (@tbreloff)"]
|
||||
version = "1.0.1"
|
||||
version = "1.0.6"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
@@ -46,7 +46,7 @@ RecipesBase = "1"
|
||||
Reexport = "0.2"
|
||||
Requires = "0.5, 1.0"
|
||||
Showoff = "0.3.1"
|
||||
StatsBase = "0.32"
|
||||
StatsBase = "0.32, 0.33"
|
||||
julia = "1"
|
||||
|
||||
[extras]
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
module Plots
|
||||
|
||||
if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel"))
|
||||
@eval Base.Experimental.@optlevel 1
|
||||
end
|
||||
|
||||
const _current_plots_version = VersionNumber(split(first(filter(line -> occursin("version", line), readlines(normpath(@__DIR__, "..", "Project.toml")))), "\"")[2])
|
||||
|
||||
using Reexport
|
||||
|
||||
+6
-3
@@ -267,6 +267,7 @@ const _series_defaults = KW(
|
||||
:bar_edges => false,
|
||||
:xerror => nothing,
|
||||
:yerror => nothing,
|
||||
:zerror => nothing,
|
||||
:ribbon => nothing,
|
||||
:quiver => nothing,
|
||||
:arrow => nothing, # allows for adding arrows to line/path... call `arrow(args...)`
|
||||
@@ -568,17 +569,18 @@ add_aliases(:bins, :bin, :nbin, :nbins, :nb)
|
||||
add_aliases(:ribbon, :rib)
|
||||
add_aliases(:annotations, :ann, :anns, :annotate, :annotation)
|
||||
add_aliases(:xguide, :xlabel, :xlab, :xl)
|
||||
add_aliases(:xlims, :xlim, :xlimit, :xlimits)
|
||||
add_aliases(:xlims, :xlim, :xlimit, :xlimits, :xrange)
|
||||
add_aliases(:xticks, :xtick)
|
||||
add_aliases(:xrotation, :xrot, :xr)
|
||||
add_aliases(:yguide, :ylabel, :ylab, :yl)
|
||||
add_aliases(:ylims, :ylim, :ylimit, :ylimits)
|
||||
add_aliases(:ylims, :ylim, :ylimit, :ylimits, :yrange)
|
||||
add_aliases(:yticks, :ytick)
|
||||
add_aliases(:yrotation, :yrot, :yr)
|
||||
add_aliases(:zguide, :zlabel, :zlab, :zl)
|
||||
add_aliases(:zlims, :zlim, :zlimit, :zlimits)
|
||||
add_aliases(:zticks, :ztick)
|
||||
add_aliases(:zrotation, :zrot, :zr)
|
||||
add_aliases(:guidefontsize, :labelfontsize)
|
||||
add_aliases(:fill_z, :fillz, :fz, :surfacecolor, :surfacecolour, :sc, :surfcolor, :surfcolour)
|
||||
add_aliases(:legend, :leg, :key)
|
||||
add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title)
|
||||
@@ -593,6 +595,7 @@ add_aliases(:color_palette, :palette)
|
||||
add_aliases(:overwrite_figure, :clf, :clearfig, :overwrite, :reuse)
|
||||
add_aliases(:xerror, :xerr, :xerrorbar)
|
||||
add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
|
||||
add_aliases(:zerror, :zerr, :zerrorbar)
|
||||
add_aliases(:quiver, :velocity, :quiver2d, :gradient, :vectorfield)
|
||||
add_aliases(:normalize, :norm, :normed, :normalized)
|
||||
add_aliases(:show_empty_bins, :showemptybins, :showempty, :show_empty)
|
||||
@@ -1015,7 +1018,7 @@ function preprocessArgs!(plotattributes::AKW)
|
||||
end
|
||||
# handle axes args
|
||||
for k in _axis_args
|
||||
if haskey(plotattributes, k)
|
||||
if haskey(plotattributes, k) && k !== :link
|
||||
v = plotattributes[k]
|
||||
for letter in (:x, :y, :z)
|
||||
lk = Symbol(letter, k)
|
||||
|
||||
+1
-1
@@ -211,7 +211,7 @@ const _base_supported_args = [
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:smooth,
|
||||
:xerror, :yerror,
|
||||
:xerror, :yerror, :zerror,
|
||||
:subplot,
|
||||
:x, :y, :z,
|
||||
:show, :size,
|
||||
|
||||
+4
-3
@@ -1424,8 +1424,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
|
||||
# border
|
||||
intensity = sp[:framestyle] == :semi ? 0.5 : 1.0
|
||||
intensity = sp[:framestyle] == :semi ? 0.5 : 1
|
||||
if sp[:framestyle] in (:box, :semi)
|
||||
GR.setclip(0)
|
||||
gr_set_line(intensity, :solid, xaxis[:foreground_color_border])
|
||||
gr_set_transparency(xaxis[:foreground_color_border], intensity)
|
||||
gr_polyline(coords(xborder_segs)...)
|
||||
@@ -1808,7 +1809,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
if sp[:legend] == :inline && should_add_to_legend(series)
|
||||
gr_set_font(legendfont(sp))
|
||||
gr_set_textcolor(plot_color(sp[:legendfontcolor]))
|
||||
if sp[:yaxis][:mirror]
|
||||
if sp[:yaxis][:mirror]
|
||||
(_,i) = sp[:xaxis][:flip] ? findmax(x) : findmin(x)
|
||||
GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF)
|
||||
offset = -0.01
|
||||
@@ -1827,7 +1828,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
hascolorbar(sp) && gr_draw_colorbar(cbar, sp, get_clims(sp))
|
||||
|
||||
# add the legend
|
||||
if !(sp[:legend] in(:none, :inline))
|
||||
if !(sp[:legend] in(:none, :inline))
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
GR.setscale(0)
|
||||
|
||||
+100
-51
@@ -104,14 +104,20 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
end
|
||||
|
||||
for sp in plt.subplots
|
||||
bb = bbox(sp)
|
||||
sp_width = width(bb)
|
||||
sp_height = height(bb)
|
||||
dx, dy = bb.x0
|
||||
# TODO: does this hold at every scale?
|
||||
if sp[:legend] in (:outertopright, nothing)
|
||||
dx *= 1.2
|
||||
end
|
||||
bb1 = sp.plotarea
|
||||
bb2 = bbox(sp)
|
||||
sp_width = width(bb2)
|
||||
sp_height = height(bb2)
|
||||
dx, dy = bb2.x0
|
||||
lpad = leftpad(sp) + sp[:left_margin]
|
||||
rpad = rightpad(sp) + sp[:right_margin]
|
||||
tpad = toppad(sp) + sp[:top_margin]
|
||||
bpad = bottompad(sp) + sp[:bottom_margin]
|
||||
dx += lpad
|
||||
dy += tpad
|
||||
axis_height = sp_height - (tpad + bpad)
|
||||
axis_width = sp_width - (rpad + lpad)
|
||||
|
||||
cstr = plot_color(sp[:background_color_legend])
|
||||
a = alpha(cstr)
|
||||
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
|
||||
@@ -164,9 +170,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
"xshift" => string(dx),
|
||||
"yshift" => string(-dy),
|
||||
)
|
||||
sp_width > 0 * mm ? push!(axis_opt, "width" => string(sp_width)) :
|
||||
sp_width > 0 * mm ? push!(axis_opt, "width" => string(axis_width)) :
|
||||
nothing
|
||||
sp_height > 0 * mm ? push!(axis_opt, "height" => string(sp_height)) :
|
||||
sp_height > 0 * mm ? push!(axis_opt, "height" => string(axis_height)) :
|
||||
nothing
|
||||
# legend position
|
||||
if sp[:legend] isa Tuple
|
||||
@@ -174,9 +180,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
push!(axis_opt["legend style"], "at={($x, $y)}")
|
||||
else
|
||||
push!(
|
||||
axis_opt,
|
||||
"legend pos" =>
|
||||
get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"),
|
||||
axis_opt["legend style"],
|
||||
get(_pgfplotsx_legend_pos, sp[:legend], ("at" => string((1.02, 1)), "anchor" => "north west"))...
|
||||
)
|
||||
end
|
||||
for letter in (:x, :y, :z)
|
||||
@@ -352,17 +357,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
series_index,
|
||||
)
|
||||
end
|
||||
# add series annotations
|
||||
anns = series[:series_annotations]
|
||||
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
|
||||
pgfx_add_annotation!(
|
||||
axis,
|
||||
xi,
|
||||
yi,
|
||||
PlotText(str, fnt),
|
||||
pgfx_thickness_scaling(series),
|
||||
)
|
||||
end
|
||||
# add to legend?
|
||||
if sp[:legend] != :none
|
||||
leg_entry = if opt[:label] isa AVec
|
||||
@@ -388,15 +382,26 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
end
|
||||
end
|
||||
end # for segments
|
||||
# add subplot annotations
|
||||
for ann in sp[:annotations]
|
||||
# add series annotations
|
||||
anns = series[:series_annotations]
|
||||
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
|
||||
pgfx_add_annotation!(
|
||||
axis,
|
||||
locate_annotation(sp, ann...)...,
|
||||
pgfx_thickness_scaling(sp),
|
||||
xi,
|
||||
yi,
|
||||
PlotText(str, fnt),
|
||||
pgfx_thickness_scaling(series),
|
||||
)
|
||||
end
|
||||
end # for series
|
||||
# add subplot annotations
|
||||
for ann in sp[:annotations]
|
||||
pgfx_add_annotation!(
|
||||
axis,
|
||||
locate_annotation(sp, ann...)...,
|
||||
pgfx_thickness_scaling(sp),
|
||||
)
|
||||
end
|
||||
push!(the_plot, axis)
|
||||
if length(plt.o.the_plot.elements) > 0
|
||||
plt.o.the_plot.elements[1] = the_plot
|
||||
@@ -405,6 +410,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
end
|
||||
end # for subplots
|
||||
pgfx_plot.is_created = true
|
||||
pgfx_plot.was_shown = false
|
||||
end # if
|
||||
return pgfx_plot
|
||||
end
|
||||
@@ -604,22 +610,22 @@ const _pgfplotsx_markers = KW(
|
||||
)
|
||||
|
||||
const _pgfplotsx_legend_pos = KW(
|
||||
:top => "north",
|
||||
:bottom => "south",
|
||||
:left => "west",
|
||||
:right => "east",
|
||||
:bottomleft => "south west",
|
||||
:bottomright => "south east",
|
||||
:topright => "north east",
|
||||
:topleft => "north west",
|
||||
:outertop => "north",
|
||||
:outerbottom => "outer south",
|
||||
:outerleft => "outer west",
|
||||
:outerright => "outer east",
|
||||
:outerbottomleft => "outer south west",
|
||||
:outerbottomright => "outer south east",
|
||||
:outertopright => "outer north east",
|
||||
:outertopleft => "outer north west",
|
||||
:top => ("at" => string((0.5, 0.98)), "anchor" => "north"),
|
||||
:bottom => ("at" => string((0.5, 0.02)), "anchor" => "south"),
|
||||
:left => ("at" => string((0.02, 0.5)), "anchor" => "west"),
|
||||
:right => ("at" => string((0.98, 0.5)), "anchor" => "east"),
|
||||
:bottomleft => ("at" => string((0.02, 0.02)), "anchor" => "south west"),
|
||||
:bottomright => ("at" => string((0.98, 0.02)), "anchor" => "south east"),
|
||||
:topright => ("at" => string((0.98, 0.98)), "anchor" => "north east"),
|
||||
:topleft => ("at" => string((-0.02, 0.98)), "anchor" => "north west"),
|
||||
:outertop => ("at" => string((0.5, 1.02)), "anchor" => "south"),
|
||||
:outerbottom => ("at" => string((0.5, -0.02)), "anchor" => "north"),
|
||||
:outerleft => ("at" => string((-0.02, 0.5)), "anchor" => "east"),
|
||||
:outerright => ("at" => string((1.02, 0.5)), "anchor" => "west"),
|
||||
:outerbottomleft => ("at" => string((-0.02, -0.02)), "anchor" => "north east"),
|
||||
:outerbottomright => ("at" => string((1.02, -0.02)), "anchor" => "north west"),
|
||||
:outertopright => ("at" => string((1.02, 1)), "anchor" => "north west"),
|
||||
:outertopleft => ("at" => string((-0.02, 1)), "anchor" => "north east"),
|
||||
)
|
||||
|
||||
const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
|
||||
@@ -900,6 +906,15 @@ function pgfx_sanitize_string(s::AbstractString)
|
||||
s = replace(s, r"\\?\%" => "\\%")
|
||||
s = replace(s, r"\\?\_" => "\\_")
|
||||
s = replace(s, r"\\?\&" => "\\&")
|
||||
s = replace(s, r"\\?\{" => "\\{")
|
||||
s = replace(s, r"\\?\}" => "\\}")
|
||||
end
|
||||
@require LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" begin
|
||||
using .LaTeXStrings
|
||||
function pgfx_sanitize_string(s::LaTeXString)
|
||||
s = replace(s, r"\\?\#" => "\\#")
|
||||
s = replace(s, r"\\?\%" => "\\%")
|
||||
end
|
||||
end
|
||||
function pgfx_sanitize_plot!(plt)
|
||||
for (key, value) in plt.attr
|
||||
@@ -998,6 +1013,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
# ticks on or off
|
||||
if axis[:ticks] in (nothing, false, :none) || framestyle == :none
|
||||
push!(opt, "$(letter)majorticks" => "false")
|
||||
elseif framestyle in (:grid, :zerolines)
|
||||
push!(opt, "$letter tick style" => PGFPlotsX.Options("draw" => "none"))
|
||||
end
|
||||
|
||||
# grid on or off
|
||||
@@ -1013,6 +1030,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
push!(opt, string(letter, :min) => lims[1], string(letter, :max) => lims[2])
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||
# ticks
|
||||
ticks = get_ticks(sp, axis)
|
||||
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||
tick_values =
|
||||
@@ -1078,6 +1096,37 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
axis[:gridstyle],
|
||||
),
|
||||
)
|
||||
|
||||
# minor ticks
|
||||
# NOTE: PGFPlots would provide "minor x ticks num", but this only places minor ticks
|
||||
# between major ticks and not outside first and last tick to the axis limits.
|
||||
# Hence, we hack around with extra ticks. Unfortunately this conflicts with
|
||||
# `:zerolines` framestyle hack. So minor ticks are not working with
|
||||
# `:zerolines`.
|
||||
minor_ticks = get_minor_ticks(sp, axis, ticks)
|
||||
if minor_ticks !== nothing
|
||||
minor_ticks =
|
||||
ispolar(sp) && letter == :x ? [rad2deg.(minor_ticks)[3:end]..., 360, 405] :
|
||||
minor_ticks
|
||||
push!(
|
||||
opt,
|
||||
string("extra ", letter, " ticks") => string("{", join(minor_ticks, ","), "}"),
|
||||
)
|
||||
push!(opt, string("extra ", letter, " tick labels") => "")
|
||||
push!(
|
||||
opt,
|
||||
string("extra ", letter, " tick style") => PGFPlotsX.Options(
|
||||
"grid" => axis[:minorgrid] ? "major" : "none",
|
||||
string(letter, " grid style") => pgfx_linestyle(
|
||||
pgfx_thickness_scaling(sp) * axis[:minorgridlinewidth],
|
||||
axis[:foreground_color_minor_grid],
|
||||
axis[:minorgridalpha],
|
||||
axis[:minorgridstyle],
|
||||
),
|
||||
"major tick length" => axis[:minorticks] ? "0.1cm" : "0"
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# framestyle
|
||||
@@ -1099,7 +1148,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
opt,
|
||||
string("extra ", letter, " tick style") => PGFPlotsX.Options(
|
||||
"grid" => "major",
|
||||
"major grid style" => pgfx_linestyle(
|
||||
string(letter, " grid style") => pgfx_linestyle(
|
||||
pgfx_thickness_scaling(sp),
|
||||
axis[:foreground_color_border],
|
||||
1.0,
|
||||
@@ -1129,12 +1178,12 @@ end
|
||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot{PGFPlotsXBackend})
|
||||
# TODO: make padding more intelligent
|
||||
# TODO: how to include margins properly?
|
||||
# sp.minpad = (50mm + sp[:left_margin],
|
||||
# 0mm + sp[:top_margin],
|
||||
# 50mm + sp[:right_margin],
|
||||
# 0mm + sp[:bottom_margin])
|
||||
leg = sp[:legend]
|
||||
if leg in (:best, :outertopright, :outerright, :outerbottomright) || (leg isa Tuple && leg[1] >= 1)
|
||||
sp.minpad = (0mm, 0mm, 5mm, 0mm)
|
||||
else
|
||||
sp.minpad = (0mm, 0mm, 0mm, 0mm)
|
||||
end
|
||||
end
|
||||
|
||||
function _create_backend_figure(plt::Plot{PGFPlotsXBackend})
|
||||
|
||||
@@ -43,7 +43,7 @@ _display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt))
|
||||
@require WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" begin
|
||||
function WebIO.render(plt::Plot{PlotlyJSBackend})
|
||||
plt_html = sprint(show, MIME("text/html"), plt)
|
||||
return WebIO.render(dom"div"(innerHTML=plt_html))
|
||||
return WebIO.render(WebIO.dom"div"(innerHTML=plt_html))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -934,6 +934,55 @@ const _examples = PlotExample[
|
||||
end,
|
||||
],
|
||||
),
|
||||
PlotExample(
|
||||
"Linked axes",
|
||||
"",
|
||||
[
|
||||
quote
|
||||
begin
|
||||
x = -5:0.1:5
|
||||
plot(plot(x, x->x^2), plot(x, x->sin(x)), layout = 2, link = :y)
|
||||
end
|
||||
end,
|
||||
],
|
||||
),
|
||||
PlotExample(
|
||||
"Error bars and array type recipes",
|
||||
"",
|
||||
[
|
||||
quote
|
||||
begin
|
||||
struct Measurement <: Number
|
||||
val::Float64
|
||||
err::Float64
|
||||
end
|
||||
value(m::Measurement) = m.val
|
||||
uncertainty(m::Measurement) = m.err
|
||||
|
||||
@recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:Measurement}
|
||||
if !(get(plotattributes, :seriestype, :path) in [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image])
|
||||
error_sym = Symbol(plotattributes[:letter], :error)
|
||||
plotattributes[error_sym] = uncertainty.(m)
|
||||
end
|
||||
value.(m)
|
||||
end
|
||||
|
||||
x = Measurement.(10sort(rand(10)), rand(10))
|
||||
y = Measurement.(10sort(rand(10)), rand(10))
|
||||
z = Measurement.(10sort(rand(10)), rand(10))
|
||||
surf = Measurement.((1:10) .* (1:10)', rand(10,10))
|
||||
|
||||
plot(
|
||||
scatter(x, [x y], msw = 0),
|
||||
scatter(x, y, z, msw = 0),
|
||||
heatmap(x, y, surf),
|
||||
wireframe(x, y, surf),
|
||||
legend = :topleft
|
||||
)
|
||||
end
|
||||
end,
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
# Some constants for PlotDocs and PlotReferenceImages
|
||||
@@ -946,6 +995,7 @@ _backend_skips = Dict(
|
||||
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30, 31, 34, 37, 38, 39],
|
||||
:pgfplotsx => [ 6, # images
|
||||
10, # histogram2d
|
||||
16, # pgfplots thinks the upper panel is too small
|
||||
22, # contourf
|
||||
23, # pie
|
||||
32, # spy
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ end
|
||||
function _add_errorbar_kw(kw_list::Vector{KW}, kw::AKW)
|
||||
# handle error bars by creating new recipedata data... these will have
|
||||
# the same recipedata index as the recipedata they are copied from
|
||||
for esym in (:xerror, :yerror)
|
||||
for esym in (:xerror, :yerror, :zerror)
|
||||
if get(kw, esym, nothing) !== nothing
|
||||
# we make a copy of the KW and apply an errorbar recipe
|
||||
errkw = copy(kw)
|
||||
|
||||
+46
-33
@@ -1012,49 +1012,62 @@ function error_zipit(ebar)
|
||||
end
|
||||
end
|
||||
|
||||
function error_coords(xorig, yorig, ebar)
|
||||
# init empty x/y, and zip errors if passed Tuple{Vector,Vector}
|
||||
x, y = Array{float_extended_type(xorig)}(undef, 0), Array{Float64}(undef, 0)
|
||||
# for each point, create a line segment from the bottom to the top of the errorbar
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
xi = _cycle(xorig, i)
|
||||
yi = _cycle(yorig, i)
|
||||
ebi = _cycle(ebar, i)
|
||||
nanappend!(x, [xi, xi])
|
||||
e1, e2 = if istuple(ebi)
|
||||
first(ebi), last(ebi)
|
||||
elseif isscalar(ebi)
|
||||
ebi, ebi
|
||||
else
|
||||
error("unexpected ebi type $(typeof(ebi)) for errorbar: $ebi")
|
||||
error_tuple(x) = x, x
|
||||
error_tuple(x::Tuple) = x
|
||||
|
||||
function error_coords(errorbar, errordata, otherdata...)
|
||||
ed = Vector{float_extended_type(errordata)}(undef, 0)
|
||||
od = [Float64[] for _ in otherdata]
|
||||
for (i, edi) in enumerate(errordata)
|
||||
for (j, odj) in enumerate(otherdata)
|
||||
odi = _cycle(odj, i)
|
||||
nanappend!(od[j], [odi, odi])
|
||||
end
|
||||
nanappend!(y, [yi - e1, yi + e2])
|
||||
e1, e2 = error_tuple(_cycle(errorbar, i))
|
||||
nanappend!(ed, [edi - e1, edi + e2])
|
||||
end
|
||||
x, y
|
||||
return (ed, od...)
|
||||
end
|
||||
|
||||
# we will create a series of path segments, where each point represents one
|
||||
# side of an errorbar
|
||||
@recipe function f(::Type{Val{:yerror}}, x, y, z)
|
||||
error_style!(plotattributes)
|
||||
markershape := :hline
|
||||
plotattributes[:x], plotattributes[:y] = error_coords(
|
||||
plotattributes[:x],
|
||||
plotattributes[:y],
|
||||
error_zipit(plotattributes[:yerror]),
|
||||
)
|
||||
()
|
||||
end
|
||||
@deps yerror path
|
||||
|
||||
@recipe function f(::Type{Val{:xerror}}, x, y, z)
|
||||
error_style!(plotattributes)
|
||||
markershape := :vline
|
||||
plotattributes[:y], plotattributes[:x] = error_coords(
|
||||
plotattributes[:y],
|
||||
plotattributes[:x],
|
||||
error_zipit(plotattributes[:xerror]),
|
||||
)
|
||||
xerr = error_zipit(plotattributes[:xerror])
|
||||
if z === nothing
|
||||
plotattributes[:x], plotattributes[:y] = error_coords(xerr, x, y)
|
||||
else
|
||||
plotattributes[:x], plotattributes[:y], plotattributes[:z] =
|
||||
error_coords(xerr, x, y, z)
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps xerror path
|
||||
|
||||
@recipe function f(::Type{Val{:yerror}}, x, y, z)
|
||||
error_style!(plotattributes)
|
||||
markershape := :hline
|
||||
yerr = error_zipit(plotattributes[:yerror])
|
||||
if z === nothing
|
||||
plotattributes[:y], plotattributes[:x] = error_coords(yerr, y, x)
|
||||
else
|
||||
plotattributes[:y], plotattributes[:x], plotattributes[:z] =
|
||||
error_coords(yerr, y, x, z)
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps yerror path
|
||||
|
||||
@recipe function f(::Type{Val{:zerror}}, x, y, z)
|
||||
error_style!(plotattributes)
|
||||
markershape := :hline
|
||||
if z !== nothing
|
||||
zerr = error_zipit(plotattributes[:zerror])
|
||||
plotattributes[:z], plotattributes[:x], plotattributes[:y] =
|
||||
error_coords(zerr, z, x, y)
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps xerror path
|
||||
|
||||
+13
-6
@@ -216,20 +216,27 @@ function _apply_type_recipe(plotattributes, v::AbstractArray, letter)
|
||||
end
|
||||
|
||||
# special handling for Surface... need to properly unwrap and re-wrap
|
||||
_apply_type_recipe(plotattributes, v::Surface{<:AMat{<:DataPoint}}) = v
|
||||
function _apply_type_recipe(plotattributes, v::Surface)
|
||||
ret = _apply_type_recipe(plotattributes, v.surf)
|
||||
_apply_type_recipe(
|
||||
plotattributes,
|
||||
v::Surface{<:AMat{<:Union{AbstractFloat, Integer, AbstractString, Missing}}},
|
||||
letter,
|
||||
) = v
|
||||
function _apply_type_recipe(plotattributes, v::Surface, letter)
|
||||
ret = _apply_type_recipe(plotattributes, v.surf, letter)
|
||||
if typeof(ret) <: Formatted
|
||||
Formatted(Surface(ret.data), ret.formatter)
|
||||
else
|
||||
Surface(ret.data)
|
||||
Surface(ret)
|
||||
end
|
||||
end
|
||||
|
||||
# don't do anything vectors of datapoints and for nothing
|
||||
_apply_type_recipe(plotattributes, v::Nothing, letter) = v
|
||||
_apply_type_recipe(plotattributes, v::AbstractArray{<:MaybeString}, letter) = v
|
||||
_apply_type_recipe(plotattributes, v::AbstractArray{<:Union{Real, Nothing}}, letter) = v
|
||||
_apply_type_recipe(
|
||||
plotattributes,
|
||||
v::AbstractArray{<:Union{AbstractFloat, Integer, AbstractString, Missing}},
|
||||
letter,
|
||||
) = v
|
||||
|
||||
# axis args before type recipes should still be mapped to all axes
|
||||
function _preprocess_axis_args!(plotattributes)
|
||||
|
||||
+1
-1
@@ -438,7 +438,7 @@ julia> plot(1:10)
|
||||
julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))])
|
||||
```
|
||||
"""
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!(anns...; kw...) = plot!(; annotation = collect(anns), kw...)
|
||||
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
|
||||
|
||||
"Flip the current plots' x axis"
|
||||
|
||||
+1
-1
@@ -826,7 +826,7 @@ end
|
||||
|
||||
extend_to_length!(v::AbstractRange, n) = range(first(v), step = step(v), length = n)
|
||||
function extend_to_length!(v::AbstractVector, n)
|
||||
vmax = isempy(v) ? 0 : ignorenan_maximum(v)
|
||||
vmax = isempty(v) ? 0 : ignorenan_maximum(v)
|
||||
extend_by_data!(v, vmax .+ (1:(n - length(v))))
|
||||
end
|
||||
extend_by_data!(v::AbstractVector, x) = isimmutable(v) ? vcat(v, x) : push!(v, x)
|
||||
|
||||
+37
-4
@@ -245,15 +245,39 @@ end
|
||||
end # testset
|
||||
@testset "Annotations" begin
|
||||
y = rand(10)
|
||||
plot(
|
||||
pgfx_plot = plot(
|
||||
y,
|
||||
annotations = (3, y[3], Plots.text("this is \\#3", :left)),
|
||||
leg = false,
|
||||
)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
|
||||
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
|
||||
@test length(nodes) == 1
|
||||
mktempdir() do path
|
||||
file_path =joinpath(path,"annotations.tex")
|
||||
@test_nowarn savefig(pgfx_plot, file_path)
|
||||
open(file_path) do io
|
||||
lines = readlines(io)
|
||||
@test count(s -> occursin("node", s), lines) == 1
|
||||
end
|
||||
end
|
||||
annotate!([
|
||||
(5, y[5], Plots.text("this is \\#5", 16, :red, :center)),
|
||||
(10, y[10], Plots.text("this is \\#10", :right, 20, "courier")),
|
||||
])
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
|
||||
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
|
||||
@test length(nodes) == 3
|
||||
mktempdir() do path
|
||||
file_path =joinpath(path,"annotations.tex")
|
||||
@test_nowarn savefig(pgfx_plot, file_path)
|
||||
open(file_path) do io
|
||||
lines = readlines(io)
|
||||
@test count(s -> occursin("node", s), lines) == 3
|
||||
end
|
||||
end
|
||||
annotation_plot = scatter!(
|
||||
range(2, stop = 8, length = 6),
|
||||
rand(6),
|
||||
@@ -267,9 +291,18 @@ end
|
||||
Plots.text("data", :green),
|
||||
],
|
||||
)
|
||||
# mktempdir() do path
|
||||
# @test_nowarn savefig(annotation_plot, path*"annotation.pdf")
|
||||
# end
|
||||
Plots._update_plot_object(annotation_plot)
|
||||
axis_content = Plots.pgfx_axes(annotation_plot.o)[1].contents
|
||||
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
|
||||
@test length(nodes) == 9
|
||||
mktempdir() do path
|
||||
file_path =joinpath(path,"annotations.tex")
|
||||
@test_nowarn savefig(annotation_plot, file_path)
|
||||
open(file_path) do io
|
||||
lines = readlines(io)
|
||||
@test count(s -> occursin("node", s), lines) == 9
|
||||
end
|
||||
end
|
||||
end # testset
|
||||
@testset "Ribbon" begin
|
||||
aa = rand(10)
|
||||
|
||||
Reference in New Issue
Block a user