Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
a301366ef6
@ -20,6 +20,10 @@ addons:
|
|||||||
- xauth
|
- xauth
|
||||||
- xvfb
|
- xvfb
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.julia/artifacts
|
||||||
|
|
||||||
sudo: required
|
sudo: required
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
name = "Plots"
|
name = "Plots"
|
||||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||||
author = ["Tom Breloff (@tbreloff)"]
|
author = ["Tom Breloff (@tbreloff)"]
|
||||||
version = "0.29.3"
|
version = "0.29.6"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||||
@ -35,7 +35,7 @@ Contour = "0.5"
|
|||||||
FFMPEG = "0.2, 0.3"
|
FFMPEG = "0.2, 0.3"
|
||||||
FixedPointNumbers = "0.6, 0.7, 0.8"
|
FixedPointNumbers = "0.6, 0.7, 0.8"
|
||||||
GR = "0.46, 0.47"
|
GR = "0.46, 0.47"
|
||||||
GeometryTypes = "0.7"
|
GeometryTypes = "0.7, 0.8"
|
||||||
JSON = "0.21"
|
JSON = "0.21"
|
||||||
Measures = "0.3"
|
Measures = "0.3"
|
||||||
NaNMath = "0.3"
|
NaNMath = "0.3"
|
||||||
|
|||||||
@ -20,6 +20,9 @@ branches:
|
|||||||
- master
|
- master
|
||||||
- /release-.*/
|
- /release-.*/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- '%USERPROFILE%\.julia\artifacts'
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
- provider: Email
|
- provider: Email
|
||||||
on_build_success: false
|
on_build_success: false
|
||||||
|
|||||||
@ -345,7 +345,7 @@ const _subplot_defaults = KW(
|
|||||||
:legendtitlefontcolor => :match,
|
:legendtitlefontcolor => :match,
|
||||||
:annotations => [], # annotation tuples... list of (x,y,annotation)
|
:annotations => [], # annotation tuples... list of (x,y,annotation)
|
||||||
:projection => :none, # can also be :polar or :3d
|
:projection => :none, # can also be :polar or :3d
|
||||||
:aspect_ratio => :none, # choose from :none or :equal
|
:aspect_ratio => :auto, # choose from :none or :equal
|
||||||
:margin => 1mm,
|
:margin => 1mm,
|
||||||
:left_margin => :match,
|
:left_margin => :match,
|
||||||
:top_margin => :match,
|
:top_margin => :match,
|
||||||
|
|||||||
138
src/backends.jl
138
src/backends.jl
@ -673,37 +673,86 @@ const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
|||||||
|
|
||||||
const _pgfplotsx_attr = merge_with_base_supported([
|
const _pgfplotsx_attr = merge_with_base_supported([
|
||||||
:annotations,
|
:annotations,
|
||||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
:background_color_legend,
|
||||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
:background_color_inside,
|
||||||
:foreground_color_text, :foreground_color_border,
|
:background_color_outside,
|
||||||
|
:foreground_color_legend,
|
||||||
|
:foreground_color_grid,
|
||||||
|
:foreground_color_axis,
|
||||||
|
:foreground_color_text,
|
||||||
|
:foreground_color_border,
|
||||||
:label,
|
:label,
|
||||||
:seriescolor, :seriesalpha,
|
:seriescolor,
|
||||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
:seriesalpha,
|
||||||
:markershape, :markercolor, :markersize, :markeralpha,
|
:linecolor,
|
||||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
:linestyle,
|
||||||
:fillrange, :fillcolor, :fillalpha,
|
:linewidth,
|
||||||
|
:linealpha,
|
||||||
|
:markershape,
|
||||||
|
:markercolor,
|
||||||
|
:markersize,
|
||||||
|
:markeralpha,
|
||||||
|
:markerstrokewidth,
|
||||||
|
:markerstrokecolor,
|
||||||
|
:markerstrokealpha,
|
||||||
|
:fillrange,
|
||||||
|
:fillcolor,
|
||||||
|
:fillalpha,
|
||||||
:bins,
|
:bins,
|
||||||
:layout,
|
:layout,
|
||||||
:title, :window_title,
|
:title,
|
||||||
:guide, :lims, :ticks, :scale, :flip,
|
:window_title,
|
||||||
|
:guide,
|
||||||
|
:lims,
|
||||||
|
:ticks,
|
||||||
|
:scale,
|
||||||
|
:flip,
|
||||||
:match_dimensions,
|
:match_dimensions,
|
||||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
:titlefontfamily,
|
||||||
:titlefontrotation, :titlefontcolor,
|
:titlefontsize,
|
||||||
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
|
:titlefonthalign,
|
||||||
:legendfontrotation, :legendfontcolor,
|
:titlefontvalign,
|
||||||
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
|
:titlefontrotation,
|
||||||
:tickfontrotation, :tickfontcolor,
|
:titlefontcolor,
|
||||||
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
|
:legendfontfamily,
|
||||||
:guidefontrotation, :guidefontcolor,
|
:legendfontsize,
|
||||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
:legendfonthalign,
|
||||||
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
|
:legendfontvalign,
|
||||||
:fill_z, :line_z, :marker_z, :levels,
|
:legendfontrotation,
|
||||||
:ribbon, :quiver,
|
:legendfontcolor,
|
||||||
|
:tickfontfamily,
|
||||||
|
:tickfontsize,
|
||||||
|
:tickfonthalign,
|
||||||
|
:tickfontvalign,
|
||||||
|
:tickfontrotation,
|
||||||
|
:tickfontcolor,
|
||||||
|
:guidefontfamily,
|
||||||
|
:guidefontsize,
|
||||||
|
:guidefonthalign,
|
||||||
|
:guidefontvalign,
|
||||||
|
:guidefontrotation,
|
||||||
|
:guidefontcolor,
|
||||||
|
:grid,
|
||||||
|
:gridalpha,
|
||||||
|
:gridstyle,
|
||||||
|
:gridlinewidth,
|
||||||
|
:legend,
|
||||||
|
:legendtitle,
|
||||||
|
:colorbar,
|
||||||
|
:colorbar_title,
|
||||||
|
:colorbar_entry,
|
||||||
|
:fill_z,
|
||||||
|
:line_z,
|
||||||
|
:marker_z,
|
||||||
|
:levels,
|
||||||
|
:ribbon,
|
||||||
|
:quiver,
|
||||||
:orientation,
|
:orientation,
|
||||||
:overwrite_figure,
|
:overwrite_figure,
|
||||||
:polar,
|
:polar,
|
||||||
:aspect_ratio,
|
:aspect_ratio,
|
||||||
:normalize, :weights,
|
:normalize,
|
||||||
|
:weights,
|
||||||
:inset_subplots,
|
:inset_subplots,
|
||||||
:bar_width,
|
:bar_width,
|
||||||
:arrow,
|
:arrow,
|
||||||
@ -712,13 +761,42 @@ const _pgfplotsx_attr = merge_with_base_supported([
|
|||||||
:camera,
|
:camera,
|
||||||
:contour_labels,
|
:contour_labels,
|
||||||
])
|
])
|
||||||
const _pgfplotsx_seriestype =
|
const _pgfplotsx_seriestype = [
|
||||||
[:path, :scatter, :straightline,
|
:path,
|
||||||
:path3d, :scatter3d, :surface, :wireframe,
|
:scatter,
|
||||||
:heatmap, :contour, :contour3d,
|
:straightline,
|
||||||
:shape,
|
:path3d,
|
||||||
:steppre, :stepmid, :steppost, :ysticks, :xsticks]
|
:scatter3d,
|
||||||
|
:surface,
|
||||||
|
:wireframe,
|
||||||
|
:heatmap,
|
||||||
|
:contour,
|
||||||
|
:contour3d,
|
||||||
|
:shape,
|
||||||
|
:steppre,
|
||||||
|
:stepmid,
|
||||||
|
:steppost,
|
||||||
|
:ysticks,
|
||||||
|
:xsticks,
|
||||||
|
]
|
||||||
const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||||
const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape]
|
const _pgfplotsx_marker = [
|
||||||
|
:none,
|
||||||
|
:auto,
|
||||||
|
:circle,
|
||||||
|
:rect,
|
||||||
|
:diamond,
|
||||||
|
:utriangle,
|
||||||
|
:dtriangle,
|
||||||
|
:ltriangle,
|
||||||
|
:rtriangle,
|
||||||
|
:cross,
|
||||||
|
:xcross,
|
||||||
|
:star5,
|
||||||
|
:pentagon,
|
||||||
|
:hline,
|
||||||
|
:vline,
|
||||||
|
Shape,
|
||||||
|
]
|
||||||
const _pgfplotsx_scale = [:identity, :ln, :log2, :log10]
|
const _pgfplotsx_scale = [:identity, :ln, :log2, :log10]
|
||||||
is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true
|
is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true
|
||||||
|
|||||||
@ -305,15 +305,27 @@ end
|
|||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
# draw ONE Shape
|
# draw ONE Shape
|
||||||
function gr_draw_marker(xi, yi, msize, shape::Shape)
|
function gr_draw_marker(series, xi, yi, clims, i, msize, shape::Shape)
|
||||||
sx, sy = coords(shape)
|
sx, sy = coords(shape)
|
||||||
# convert to ndc coords (percentages of window)
|
# convert to ndc coords (percentages of window)
|
||||||
GR.selntran(0)
|
GR.selntran(0)
|
||||||
w, h = gr_plot_size
|
w, h = gr_plot_size
|
||||||
f = msize / (w + h)
|
f = msize / (w + h)
|
||||||
xi, yi = GR.wctondc(xi, yi)
|
xi, yi = GR.wctondc(xi, yi)
|
||||||
GR.fillarea(xi .+ sx .* f,
|
xs = xi .+ sx .* f
|
||||||
yi .+ sy .* f)
|
ys = yi .+ sy .* f
|
||||||
|
|
||||||
|
# draw the interior
|
||||||
|
mc = get_markercolor(series, clims, i)
|
||||||
|
gr_set_fill(mc)
|
||||||
|
gr_set_transparency(mc, get_markeralpha(series, i))
|
||||||
|
GR.fillarea(xs, ys)
|
||||||
|
|
||||||
|
# draw the shapes
|
||||||
|
msc = get_markerstrokecolor(series, i)
|
||||||
|
gr_set_line(get_markerstrokewidth(series, i), :solid, msc)
|
||||||
|
gr_set_transparency(msc, get_markerstrokealpha(series, i))
|
||||||
|
GR.polyline(xs, ys)
|
||||||
GR.selntran(1)
|
GR.selntran(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -323,7 +335,11 @@ function nominal_size()
|
|||||||
end
|
end
|
||||||
|
|
||||||
# draw ONE symbol marker
|
# draw ONE symbol marker
|
||||||
function gr_draw_marker(xi, yi, msize::Number, shape::Symbol)
|
function gr_draw_marker(series, xi, yi, clims, i, msize::Number, shape::Symbol)
|
||||||
|
GR.setborderwidth(series[:markerstrokewidth]);
|
||||||
|
gr_set_bordercolor(get_markerstrokecolor(series, i));
|
||||||
|
gr_set_markercolor(get_markercolor(series, clims, i));
|
||||||
|
gr_set_transparency(get_markeralpha(series, i))
|
||||||
GR.setmarkertype(gr_markertype[shape])
|
GR.setmarkertype(gr_markertype[shape])
|
||||||
GR.setmarkersize(0.3msize / nominal_size())
|
GR.setmarkersize(0.3msize / nominal_size())
|
||||||
GR.polymarker([xi], [yi])
|
GR.polymarker([xi], [yi])
|
||||||
@ -341,13 +357,7 @@ function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize
|
|||||||
for i=eachindex(x)
|
for i=eachindex(x)
|
||||||
msi = _cycle(msize, i)
|
msi = _cycle(msize, i)
|
||||||
shape = _cycle(shapes, i)
|
shape = _cycle(shapes, i)
|
||||||
i
|
gr_draw_marker(series, x[i], y[i], clims, i, msi, shape)
|
||||||
GR.setborderwidth(series[:markerstrokewidth]);
|
|
||||||
gr_set_bordercolor(get_markerstrokecolor(series, i));
|
|
||||||
gr_set_markercolor(get_markercolor(series, clims, i));
|
|
||||||
gr_set_transparency(get_markeralpha(series, i))
|
|
||||||
|
|
||||||
gr_draw_marker(x[i], y[i], msi, shape)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -971,7 +981,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
data_lims = gr_xy_axislims(sp)
|
data_lims = gr_xy_axislims(sp)
|
||||||
xy_lims = data_lims
|
xy_lims = data_lims
|
||||||
|
|
||||||
ratio = sp[:aspect_ratio]
|
ratio = get_aspect_ratio(sp)
|
||||||
if ratio != :none
|
if ratio != :none
|
||||||
if ratio == :equal
|
if ratio == :equal
|
||||||
ratio = 1
|
ratio = 1
|
||||||
@ -1050,11 +1060,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
if st == :pie
|
if st == :pie
|
||||||
draw_axes = false
|
draw_axes = false
|
||||||
end
|
end
|
||||||
if st == :heatmap
|
if st in (:heatmap, :image)
|
||||||
outside_ticks = true
|
outside_ticks = true
|
||||||
for ax in (sp[:xaxis], sp[:yaxis])
|
|
||||||
v = series[ax[:letter]]
|
|
||||||
end
|
|
||||||
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z]))
|
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z]))
|
||||||
xy_lims = x[1], x[end], y[1], y[end]
|
xy_lims = x[1], x[end], y[1], y[end]
|
||||||
expand_extrema!(sp[:xaxis], x)
|
expand_extrema!(sp[:xaxis], x)
|
||||||
@ -1776,8 +1783,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
|
|
||||||
elseif st == :image
|
elseif st == :image
|
||||||
z = transpose_z(series, series[:z].surf, true)'
|
z = transpose_z(series, series[:z].surf, true)'
|
||||||
|
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(z))
|
||||||
w, h = size(z)
|
w, h = size(z)
|
||||||
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
|
xmin, xmax = ignorenan_extrema(x)
|
||||||
|
ymin, ymax = ignorenan_extrema(y)
|
||||||
rgba = gr_color.(z)
|
rgba = gr_color.(z)
|
||||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -470,7 +470,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
|||||||
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
|
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
if sp[:aspect_ratio] in (1, :equal)
|
if get_aspect_ratio(sp) in (1, :equal)
|
||||||
kw[:axisEqual] = "true"
|
kw[:axisEqual] = "true"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend})
|
|||||||
old_flag = pgfx_plot.attr[:tex_output_standalone]
|
old_flag = pgfx_plot.attr[:tex_output_standalone]
|
||||||
pgfx_plot.attr[:tex_output_standalone] = true
|
pgfx_plot.attr[:tex_output_standalone] = true
|
||||||
fulltext = String(repr("application/x-tex", pgfx_plot))
|
fulltext = String(repr("application/x-tex", pgfx_plot))
|
||||||
preamble = fulltext[1:first(findfirst("\\begin{document}", fulltext))-1]
|
preamble = fulltext[1:(first(findfirst("\\begin{document}", fulltext)) - 1)]
|
||||||
pgfx_plot.attr[:tex_output_standalone] = old_flag
|
pgfx_plot.attr[:tex_output_standalone] = old_flag
|
||||||
preamble
|
preamble
|
||||||
end
|
end
|
||||||
@ -78,7 +78,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
if !pgfx_plot.is_created
|
if !pgfx_plot.is_created
|
||||||
the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options())
|
the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options())
|
||||||
bgc = plt.attr[:background_color_outside] == :match ?
|
bgc = plt.attr[:background_color_outside] == :match ?
|
||||||
plt.attr[:background_color] : plt.attr[:background_color_outside]
|
plt.attr[:background_color] : plt.attr[:background_color_outside]
|
||||||
if bgc isa Colors.Colorant
|
if bgc isa Colors.Colorant
|
||||||
cstr = plot_color(bgc)
|
cstr = plot_color(bgc)
|
||||||
a = alpha(cstr)
|
a = alpha(cstr)
|
||||||
@ -98,7 +98,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
sp_width = width(bb)
|
sp_width = width(bb)
|
||||||
sp_height = height(bb)
|
sp_height = height(bb)
|
||||||
dx, dy = bb.x0
|
dx, dy = bb.x0
|
||||||
# TODO: does this hold at every scale?
|
# TODO: does this hold at every scale?
|
||||||
if sp[:legend] in (:outertopright, nothing)
|
if sp[:legend] in (:outertopright, nothing)
|
||||||
dx *= 1.2
|
dx *= 1.2
|
||||||
end
|
end
|
||||||
@ -129,7 +129,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
) => nothing,
|
) => nothing,
|
||||||
"fill" => cstr,
|
"fill" => cstr,
|
||||||
"fill opacity" => a,
|
"fill opacity" => a,
|
||||||
"text opacity" => alpha(plot_color(sp[:legendfontcolor])),
|
"text opacity" =>
|
||||||
|
alpha(plot_color(sp[:legendfontcolor])),
|
||||||
"font" => pgfx_font(
|
"font" => pgfx_font(
|
||||||
sp[:legendfontsize],
|
sp[:legendfontsize],
|
||||||
pgfx_thickness_scaling(sp),
|
pgfx_thickness_scaling(sp),
|
||||||
@ -157,11 +158,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
else
|
else
|
||||||
push!(
|
push!(
|
||||||
axis_opt,
|
axis_opt,
|
||||||
"legend pos" => get(
|
"legend pos" =>
|
||||||
_pgfplotsx_legend_pos,
|
get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"),
|
||||||
sp[:legend],
|
|
||||||
"outer north east",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
for letter in (:x, :y, :z)
|
for letter in (:x, :y, :z)
|
||||||
@ -185,8 +183,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
PGFPlotsX.push_preamble!(
|
PGFPlotsX.push_preamble!(
|
||||||
pgfx_plot.the_plot,
|
pgfx_plot.the_plot,
|
||||||
"""\\pgfplotsset{
|
"""\\pgfplotsset{
|
||||||
colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))},
|
colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))},
|
||||||
}""",
|
}""",
|
||||||
)
|
)
|
||||||
push!(
|
push!(
|
||||||
axis_opt,
|
axis_opt,
|
||||||
@ -213,8 +211,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
push!(axis_opt, "view" => (azim, elev))
|
push!(axis_opt, "view" => (azim, elev))
|
||||||
end
|
end
|
||||||
axisf = if sp[:projection] == :polar
|
axisf = if sp[:projection] == :polar
|
||||||
# push!(axis_opt, "xmin" => 90)
|
# push!(axis_opt, "xmin" => 90)
|
||||||
# push!(axis_opt, "xmax" => 450)
|
# push!(axis_opt, "xmax" => 450)
|
||||||
PGFPlotsX.PolarAxis
|
PGFPlotsX.PolarAxis
|
||||||
else
|
else
|
||||||
PGFPlotsX.Axis
|
PGFPlotsX.Axis
|
||||||
@ -229,20 +227,21 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
sf = series[:fillrange]
|
sf = series[:fillrange]
|
||||||
series_opt = PGFPlotsX.Options(
|
series_opt = PGFPlotsX.Options(
|
||||||
"color" => single_color(opt[:linecolor]),
|
"color" => single_color(opt[:linecolor]),
|
||||||
"name path" => string(series_id)
|
"name path" => string(series_id),
|
||||||
)
|
)
|
||||||
if is3d(series) || st == :heatmap
|
if is3d(series) || st == :heatmap
|
||||||
series_func = PGFPlotsX.Plot3
|
series_func = PGFPlotsX.Plot3
|
||||||
else
|
else
|
||||||
series_func = PGFPlotsX.Plot
|
series_func = PGFPlotsX.Plot
|
||||||
end
|
end
|
||||||
if sf !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
|
if sf !== nothing &&
|
||||||
|
!isfilledcontour(series) && series[:ribbon] === nothing
|
||||||
push!(series_opt, "area legend" => nothing)
|
push!(series_opt, "area legend" => nothing)
|
||||||
end
|
end
|
||||||
if st == :heatmap
|
if st == :heatmap
|
||||||
push!(axis.options, "view" => "{0}{90}")
|
push!(axis.options, "view" => "{0}{90}")
|
||||||
end
|
end
|
||||||
# treat segments
|
# treat segments
|
||||||
segments =
|
segments =
|
||||||
if st in (:wireframe, :heatmap, :contour, :surface, :contour3d)
|
if st in (:wireframe, :heatmap, :contour, :surface, :contour3d)
|
||||||
iter_segments(surface_to_vecs(
|
iter_segments(surface_to_vecs(
|
||||||
@ -255,6 +254,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
end
|
end
|
||||||
for (i, rng) in enumerate(segments)
|
for (i, rng) in enumerate(segments)
|
||||||
segment_opt = PGFPlotsX.Options()
|
segment_opt = PGFPlotsX.Options()
|
||||||
|
if opt[:label] == ""
|
||||||
|
push!(segment_opt, "forget plot" => nothing)
|
||||||
|
end
|
||||||
segment_opt = merge(segment_opt, pgfx_linestyle(opt, i))
|
segment_opt = merge(segment_opt, pgfx_linestyle(opt, i))
|
||||||
if opt[:markershape] != :none
|
if opt[:markershape] != :none
|
||||||
marker = opt[:markershape]
|
marker = opt[:markershape]
|
||||||
@ -264,7 +266,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
scale_factor = 0.025
|
scale_factor = 0.025
|
||||||
mark_size = opt[:markersize] * scale_factor
|
mark_size = opt[:markersize] * scale_factor
|
||||||
path = join(
|
path = join(
|
||||||
["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)],
|
[
|
||||||
|
"($(x[i] * mark_size), $(y[i] * mark_size))"
|
||||||
|
for i in eachindex(x)
|
||||||
|
],
|
||||||
" -- ",
|
" -- ",
|
||||||
)
|
)
|
||||||
c = get_markercolor(series, i)
|
c = get_markercolor(series, i)
|
||||||
@ -285,38 +290,45 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
segment_opt = merge(segment_opt, pgfx_fillstyle(opt, i))
|
segment_opt = merge(segment_opt, pgfx_fillstyle(opt, i))
|
||||||
end
|
end
|
||||||
# add fillrange
|
# add fillrange
|
||||||
if sf !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
|
if sf !== nothing &&
|
||||||
|
!isfilledcontour(series) && series[:ribbon] === nothing
|
||||||
if sf isa Number || sf isa AVec
|
if sf isa Number || sf isa AVec
|
||||||
pgfx_fillrange_series!( axis, series, series_func, i, _cycle(sf, rng), rng)
|
pgfx_fillrange_series!(
|
||||||
|
axis,
|
||||||
|
series,
|
||||||
|
series_func,
|
||||||
|
i,
|
||||||
|
_cycle(sf, rng),
|
||||||
|
rng,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
|
if i == 1 && sp[:legend] != :none && pgfx_should_add_to_legend(series)
|
||||||
pgfx_filllegend!(series_opt, opt)
|
pgfx_filllegend!(series_opt, opt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# series
|
# series
|
||||||
#
|
#
|
||||||
coordinates = pgfx_series_coordinates!(
|
coordinates =
|
||||||
sp,
|
pgfx_series_coordinates!(sp, series, segment_opt, opt, rng)
|
||||||
series,
|
segment_plot =
|
||||||
segment_opt,
|
series_func(merge(series_opt, segment_opt), coordinates)
|
||||||
opt,
|
|
||||||
rng,
|
|
||||||
)
|
|
||||||
segment_plot = series_func(
|
|
||||||
merge(series_opt, segment_opt),
|
|
||||||
coordinates,
|
|
||||||
)
|
|
||||||
push!(axis, segment_plot)
|
push!(axis, segment_plot)
|
||||||
# fill between functions
|
# fill between functions
|
||||||
if sf isa Tuple && series[:ribbon] === nothing
|
if sf isa Tuple && series[:ribbon] === nothing
|
||||||
sf1, sf2 = sf
|
sf1, sf2 = sf
|
||||||
@assert sf1 == series_index "First index of the tuple has to match the current series index."
|
@assert sf1 == series_index "First index of the tuple has to match the current series index."
|
||||||
push!(axis, series_func(
|
push!(
|
||||||
merge(pgfx_fillstyle(opt, series_index), PGFPlotsX.Options("forget plot" => nothing)),
|
axis,
|
||||||
"fill between [of=$series_id and $(_pgfplotsx_series_ids[Symbol(string(sf2))])]"
|
series_func(
|
||||||
))
|
merge(
|
||||||
|
pgfx_fillstyle(opt, series_index),
|
||||||
|
PGFPlotsX.Options("forget plot" => nothing),
|
||||||
|
),
|
||||||
|
"fill between [of=$series_id and $(_pgfplotsx_series_ids[Symbol(string(sf2))])]",
|
||||||
|
),
|
||||||
|
)
|
||||||
end
|
end
|
||||||
# add ribbons?
|
# add ribbons?
|
||||||
ribbon = series[:ribbon]
|
ribbon = series[:ribbon]
|
||||||
if ribbon !== nothing
|
if ribbon !== nothing
|
||||||
pgfx_add_ribbons!(
|
pgfx_add_ribbons!(
|
||||||
@ -327,18 +339,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
series_index,
|
series_index,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
# add to legend?
|
# add to legend?
|
||||||
if i == 1 &&
|
if i == 1 && sp[:legend] != :none && pgfx_should_add_to_legend(series)
|
||||||
opt[:label] != "" &&
|
|
||||||
sp[:legend] != :none && should_add_to_legend(series)
|
|
||||||
leg_opt = PGFPlotsX.Options()
|
leg_opt = PGFPlotsX.Options()
|
||||||
if ribbon !== nothing
|
if ribbon !== nothing
|
||||||
pgfx_filllegend!(axis.contents[end-3].options, opt)
|
pgfx_filllegend!(axis.contents[end - 3].options, opt)
|
||||||
end
|
end
|
||||||
legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false)
|
legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false)
|
||||||
push!(axis, legend)
|
push!(axis, legend)
|
||||||
end
|
end
|
||||||
# add series annotations
|
# add series annotations
|
||||||
anns = series[:series_annotations]
|
anns = series[:series_annotations]
|
||||||
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
|
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
|
||||||
pgfx_add_annotation!(
|
pgfx_add_annotation!(
|
||||||
@ -352,7 +362,11 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
|||||||
end
|
end
|
||||||
# add subplot annotations
|
# add subplot annotations
|
||||||
for ann in sp[:annotations]
|
for ann in sp[:annotations]
|
||||||
pgfx_add_annotation!(axis, locate_annotation(sp, ann...)..., pgfx_thickness_scaling(sp))
|
pgfx_add_annotation!(
|
||||||
|
axis,
|
||||||
|
locate_annotation(sp, ann...)...,
|
||||||
|
pgfx_thickness_scaling(sp),
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end # for series
|
end # for series
|
||||||
push!(the_plot, axis)
|
push!(the_plot, axis)
|
||||||
@ -495,7 +509,7 @@ function pgfx_series_coordinates!(
|
|||||||
)
|
)
|
||||||
push!(
|
push!(
|
||||||
segment_opt,
|
segment_opt,
|
||||||
"contour prepared" => PGFPlotsX.Options("labels" => opt[:contour_labels],),
|
"contour prepared" => PGFPlotsX.Options("labels" => opt[:contour_labels]),
|
||||||
)
|
)
|
||||||
return PGFPlotsX.Table(Contour.contours(args..., opt[:levels]))
|
return PGFPlotsX.Table(Contour.contours(args..., opt[:levels]))
|
||||||
end
|
end
|
||||||
@ -508,7 +522,7 @@ function pgfx_series_coordinates!(
|
|||||||
xs, ys, zs = collect(args)
|
xs, ys, zs = collect(args)
|
||||||
push!(
|
push!(
|
||||||
segment_opt,
|
segment_opt,
|
||||||
"contour filled" => PGFPlotsX.Options("labels" => opt[:contour_labels],),
|
"contour filled" => PGFPlotsX.Options("labels" => opt[:contour_labels]),
|
||||||
"point meta" => "explicit",
|
"point meta" => "explicit",
|
||||||
"shader" => "flat",
|
"shader" => "flat",
|
||||||
)
|
)
|
||||||
@ -519,10 +533,10 @@ function pgfx_series_coordinates!(
|
|||||||
end
|
end
|
||||||
|
|
||||||
cs = join(
|
cs = join(
|
||||||
[join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (
|
[
|
||||||
i,
|
join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ")
|
||||||
y,
|
for (i, y) in enumerate(ys)
|
||||||
) in enumerate(ys)],
|
],
|
||||||
"\n\n",
|
"\n\n",
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
@ -575,11 +589,8 @@ const _pgfx_framestyle_defaults = Dict(:semi => :box)
|
|||||||
|
|
||||||
# we use the anchors to define orientations for example to align left
|
# we use the anchors to define orientations for example to align left
|
||||||
# one needs to use the right edge as anchor
|
# one needs to use the right edge as anchor
|
||||||
const _pgfx_annotation_halign = KW(
|
const _pgfx_annotation_halign =
|
||||||
:center => "",
|
KW(:center => "", :left => "right", :right => "left")
|
||||||
:left => "right",
|
|
||||||
:right => "left",
|
|
||||||
)
|
|
||||||
## --------------------------------------------------------------------------------------
|
## --------------------------------------------------------------------------------------
|
||||||
# Generates a colormap for pgfplots based on a ColorGradient
|
# Generates a colormap for pgfplots based on a ColorGradient
|
||||||
pgfx_arrow(::Nothing) = "every arrow/.append style={-}"
|
pgfx_arrow(::Nothing) = "every arrow/.append style={-}"
|
||||||
@ -607,12 +618,9 @@ function pgfx_filllegend!(series_opt, opt)
|
|||||||
io = IOBuffer()
|
io = IOBuffer()
|
||||||
PGFPlotsX.print_tex(io, pgfx_fillstyle(opt))
|
PGFPlotsX.print_tex(io, pgfx_fillstyle(opt))
|
||||||
style = strip(String(take!(io)), ['[', ']', ' '])
|
style = strip(String(take!(io)), ['[', ']', ' '])
|
||||||
push!(
|
push!(series_opt, "legend image code/.code" => """{
|
||||||
series_opt,
|
\\draw[$style] (0cm,-0.1cm) rectangle (0.6cm,0.1cm);
|
||||||
"legend image code/.code" => """{
|
}""")
|
||||||
\\draw[$style] (0cm,-0.1cm) rectangle (0.6cm,0.1cm);
|
|
||||||
}""",
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function pgfx_colormap(grad::ColorGradient)
|
function pgfx_colormap(grad::ColorGradient)
|
||||||
@ -631,9 +639,7 @@ function pgfx_framestyle(style::Symbol)
|
|||||||
return style
|
return style
|
||||||
else
|
else
|
||||||
default_style = get(_pgfx_framestyle_defaults, style, :axes)
|
default_style = get(_pgfx_framestyle_defaults, style, :axes)
|
||||||
@warn(
|
@warn( "Framestyle :$style is not (yet) supported by the PGFPlotsX backend. :$default_style was cosen instead.",)
|
||||||
"Framestyle :$style is not (yet) supported by the PGFPlotsX backend. :$default_style was cosen instead.",
|
|
||||||
)
|
|
||||||
default_style
|
default_style
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -675,6 +681,25 @@ function pgfx_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
|
|||||||
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
|
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function pgfx_should_add_to_legend(series::Series)
|
||||||
|
series.plotattributes[:primary] && series.plotattributes[:label] != "" &&
|
||||||
|
!(
|
||||||
|
series.plotattributes[:seriestype] in (
|
||||||
|
:hexbin,
|
||||||
|
:bins2d,
|
||||||
|
:histogram2d,
|
||||||
|
:hline,
|
||||||
|
:vline,
|
||||||
|
:contour,
|
||||||
|
:contourf,
|
||||||
|
:contour3d,
|
||||||
|
:heatmap,
|
||||||
|
:pie,
|
||||||
|
:image,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
function pgfx_marker(plotattributes, i = 1)
|
function pgfx_marker(plotattributes, i = 1)
|
||||||
shape = _cycle(plotattributes[:markershape], i)
|
shape = _cycle(plotattributes[:markershape], i)
|
||||||
cstr = plot_color(
|
cstr = plot_color(
|
||||||
@ -687,19 +712,22 @@ function pgfx_marker(plotattributes, i = 1)
|
|||||||
get_markerstrokealpha(plotattributes, i),
|
get_markerstrokealpha(plotattributes, i),
|
||||||
)
|
)
|
||||||
a_stroke = alpha(cstr_stroke)
|
a_stroke = alpha(cstr_stroke)
|
||||||
mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 *
|
mark_size =
|
||||||
_cycle(plotattributes[:markersize], i)
|
pgfx_thickness_scaling(plotattributes) *
|
||||||
|
0.5 *
|
||||||
|
_cycle(plotattributes[:markersize], i)
|
||||||
return PGFPlotsX.Options(
|
return PGFPlotsX.Options(
|
||||||
"mark" => shape isa Shape ? "PlotsShape$i" :
|
"mark" =>
|
||||||
get(_pgfplotsx_markers, shape, "*"),
|
shape isa Shape ? "PlotsShape$i" : get(_pgfplotsx_markers, shape, "*"),
|
||||||
"mark size" => "$mark_size pt",
|
"mark size" => "$mark_size pt",
|
||||||
"mark options" => PGFPlotsX.Options(
|
"mark options" => PGFPlotsX.Options(
|
||||||
"color" => cstr_stroke,
|
"color" => cstr_stroke,
|
||||||
"draw opacity" => a_stroke,
|
"draw opacity" => a_stroke,
|
||||||
"fill" => cstr,
|
"fill" => cstr,
|
||||||
"fill opacity" => a,
|
"fill opacity" => a,
|
||||||
"line width" => pgfx_thickness_scaling(plotattributes) *
|
"line width" =>
|
||||||
_cycle(plotattributes[:markerstrokewidth], i),
|
pgfx_thickness_scaling(plotattributes) *
|
||||||
|
_cycle(plotattributes[:markerstrokewidth], i),
|
||||||
"rotate" => if shape == :dtriangle
|
"rotate" => if shape == :dtriangle
|
||||||
180
|
180
|
||||||
elseif shape == :rtriangle
|
elseif shape == :rtriangle
|
||||||
@ -725,15 +753,15 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1)
|
|||||||
push!(
|
push!(
|
||||||
o,
|
o,
|
||||||
[
|
[
|
||||||
"\\node",
|
"\\node",
|
||||||
PGFPlotsX.Options(
|
PGFPlotsX.Options(
|
||||||
get(_pgfx_annotation_halign, val.font.halign, "") => nothing,
|
get(_pgfx_annotation_halign, val.font.halign, "") => nothing,
|
||||||
"color" => cstr,
|
"color" => cstr,
|
||||||
"draw opacity" => convert(Float16, a),
|
"draw opacity" => convert(Float16, a),
|
||||||
"rotate" => val.font.rotation,
|
"rotate" => val.font.rotation,
|
||||||
"font" => pgfx_font(val.font.pointsize, thickness_scaling),
|
"font" => pgfx_font(val.font.pointsize, thickness_scaling),
|
||||||
),
|
),
|
||||||
" at (axis cs:$x, $y) {$(val.str)};",
|
" at (axis cs:$x, $y) {$(val.str)};",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -803,7 +831,7 @@ function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng)
|
|||||||
push!(fillrange_opt, "forget plot" => nothing)
|
push!(fillrange_opt, "forget plot" => nothing)
|
||||||
opt = series.plotattributes
|
opt = series.plotattributes
|
||||||
args = is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) :
|
args = is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) :
|
||||||
(opt[:x][rng], opt[:y][rng])
|
(opt[:x][rng], opt[:y][rng])
|
||||||
push!(
|
push!(
|
||||||
axis,
|
axis,
|
||||||
PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...)),
|
PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...)),
|
||||||
@ -854,7 +882,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
|||||||
opt,
|
opt,
|
||||||
string(letter, "label style") => PGFPlotsX.Options(
|
string(letter, "label style") => PGFPlotsX.Options(
|
||||||
labelpos => nothing,
|
labelpos => nothing,
|
||||||
"font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)),
|
"font" =>
|
||||||
|
pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)),
|
||||||
"color" => cstr,
|
"color" => cstr,
|
||||||
"draw opacity" => α,
|
"draw opacity" => α,
|
||||||
"rotate" => axis[:guidefontrotation],
|
"rotate" => axis[:guidefontrotation],
|
||||||
@ -868,10 +897,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
|||||||
scale = axis[:scale]
|
scale = axis[:scale]
|
||||||
if scale in (:log2, :ln, :log10)
|
if scale in (:log2, :ln, :log10)
|
||||||
push!(opt, string(letter, :mode) => "log")
|
push!(opt, string(letter, :mode) => "log")
|
||||||
scale == :ln || push!(
|
scale == :ln ||
|
||||||
opt,
|
push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)")
|
||||||
"log basis $letter" => "$(scale == :log2 ? 2 : 10)",
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# ticks on or off
|
# ticks on or off
|
||||||
@ -888,14 +915,15 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
|||||||
|
|
||||||
# limits
|
# limits
|
||||||
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) :
|
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) :
|
||||||
axis_limits(sp, letter)
|
axis_limits(sp, letter)
|
||||||
push!(opt, string(letter, :min) => lims[1], string(letter, :max) => lims[2])
|
push!(opt, string(letter, :min) => lims[1], string(letter, :max) => lims[2])
|
||||||
|
|
||||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||||
ticks = get_ticks(sp, axis)
|
ticks = get_ticks(sp, axis)
|
||||||
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||||
tick_values = ispolar(sp) && letter == :x ?
|
tick_values =
|
||||||
[rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
|
ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] :
|
||||||
|
ticks[1]
|
||||||
push!(
|
push!(
|
||||||
opt,
|
opt,
|
||||||
string(letter, "tick") => string("{", join(tick_values, ","), "}"),
|
string(letter, "tick") => string("{", join(tick_values, ","), "}"),
|
||||||
@ -911,44 +939,37 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
|||||||
end
|
end
|
||||||
push!(
|
push!(
|
||||||
opt,
|
opt,
|
||||||
string(letter, "ticklabels") => string(
|
string(letter, "ticklabels") =>
|
||||||
"{\$",
|
string("{\$", join(tick_labels, "\$,\$"), "\$}"),
|
||||||
join(tick_labels, "\$,\$"),
|
|
||||||
"\$}",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
elseif axis[:showaxis]
|
elseif axis[:showaxis]
|
||||||
tick_labels = ispolar(sp) && letter == :x ?
|
tick_labels =
|
||||||
[ticks[2][3:end]..., "0", "45"] : ticks[2]
|
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] :
|
||||||
|
ticks[2]
|
||||||
if axis[:formatter] in (:scientific, :auto)
|
if axis[:formatter] in (:scientific, :auto)
|
||||||
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
|
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
|
||||||
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
|
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
|
||||||
end
|
end
|
||||||
push!(
|
push!(
|
||||||
opt,
|
opt,
|
||||||
string(letter, "ticklabels") => string(
|
string(letter, "ticklabels") =>
|
||||||
"{",
|
string("{", join(tick_labels, ","), "}"),
|
||||||
join(tick_labels, ","),
|
|
||||||
"}",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
push!(opt, string(letter, "ticklabels") => "{}")
|
push!(opt, string(letter, "ticklabels") => "{}")
|
||||||
end
|
end
|
||||||
push!(
|
push!(
|
||||||
opt,
|
opt,
|
||||||
string(letter, "tick align") => (axis[:tick_direction] == :out ?
|
string(letter, "tick align") =>
|
||||||
"outside" : "inside"),
|
(axis[:tick_direction] == :out ? "outside" : "inside"),
|
||||||
)
|
)
|
||||||
cstr = plot_color(axis[:tickfontcolor])
|
cstr = plot_color(axis[:tickfontcolor])
|
||||||
α = alpha(cstr)
|
α = alpha(cstr)
|
||||||
push!(
|
push!(
|
||||||
opt,
|
opt,
|
||||||
string(letter, "ticklabel style") => PGFPlotsX.Options(
|
string(letter, "ticklabel style") => PGFPlotsX.Options(
|
||||||
"font" => pgfx_font(
|
"font" =>
|
||||||
axis[:tickfontsize],
|
pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)),
|
||||||
pgfx_thickness_scaling(sp),
|
|
||||||
),
|
|
||||||
"color" => cstr,
|
"color" => cstr,
|
||||||
"draw opacity" => α,
|
"draw opacity" => α,
|
||||||
"rotate" => axis[:tickfontrotation],
|
"rotate" => axis[:tickfontrotation],
|
||||||
@ -967,7 +988,9 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
|||||||
|
|
||||||
# framestyle
|
# framestyle
|
||||||
if framestyle in (:axes, :origin)
|
if framestyle in (:axes, :origin)
|
||||||
axispos = framestyle == :axes ? "left" : "middle"
|
axispos = axis[:mirror] ? "right" :
|
||||||
|
framestyle == :axes ? "left" : "middle"
|
||||||
|
|
||||||
if axis[:draw_arrow]
|
if axis[:draw_arrow]
|
||||||
push!(opt, string("axis ", letter, " line") => axispos)
|
push!(opt, string("axis ", letter, " line") => axispos)
|
||||||
else
|
else
|
||||||
|
|||||||
@ -108,7 +108,7 @@ function shrink_by(lo, sz, ratio)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
|
function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
|
||||||
aspect_ratio = sp[:aspect_ratio]
|
aspect_ratio = get_aspect_ratio(sp)
|
||||||
if aspect_ratio != :none
|
if aspect_ratio != :none
|
||||||
if aspect_ratio == :equal
|
if aspect_ratio == :equal
|
||||||
aspect_ratio = 1.0
|
aspect_ratio = 1.0
|
||||||
|
|||||||
@ -1155,7 +1155,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
|||||||
end
|
end
|
||||||
|
|
||||||
# aspect ratio
|
# aspect ratio
|
||||||
aratio = sp[:aspect_ratio]
|
aratio = get_aspect_ratio(sp)
|
||||||
if aratio != :none
|
if aratio != :none
|
||||||
ax."set_aspect"(isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C")
|
ax."set_aspect"(isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C")
|
||||||
end
|
end
|
||||||
|
|||||||
1420
src/examples.jl
1420
src/examples.jl
File diff suppressed because it is too large
Load Diff
434
src/recipes.jl
434
src/recipes.jl
@ -44,7 +44,7 @@ end
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
num_series(x::AMat) = size(x,2)
|
num_series(x::AMat) = size(x, 2)
|
||||||
num_series(x) = 1
|
num_series(x) = 1
|
||||||
|
|
||||||
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
|
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
|
||||||
@ -55,13 +55,26 @@ RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) wher
|
|||||||
# for seriestype `line`, need to sort by x values
|
# for seriestype `line`, need to sort by x values
|
||||||
|
|
||||||
const POTENTIAL_VECTOR_ARGUMENTS = [
|
const POTENTIAL_VECTOR_ARGUMENTS = [
|
||||||
:seriescolor, :seriesalpha,
|
:seriescolor,
|
||||||
:linecolor, :linealpha, :linewidth, :linestyle, :line_z,
|
:seriesalpha,
|
||||||
:fillcolor, :fillalpha, :fill_z,
|
:linecolor,
|
||||||
:markercolor, :markeralpha, :markershape, :marker_z,
|
:linealpha,
|
||||||
:markerstrokecolor, :markerstrokealpha,
|
:linewidth,
|
||||||
:yerror, :yerror,
|
:linestyle,
|
||||||
:series_annotations, :fillrange
|
:line_z,
|
||||||
|
:fillcolor,
|
||||||
|
:fillalpha,
|
||||||
|
:fill_z,
|
||||||
|
:markercolor,
|
||||||
|
:markeralpha,
|
||||||
|
:markershape,
|
||||||
|
:marker_z,
|
||||||
|
:markerstrokecolor,
|
||||||
|
:markerstrokealpha,
|
||||||
|
:yerror,
|
||||||
|
:yerror,
|
||||||
|
:series_annotations,
|
||||||
|
:fillrange,
|
||||||
]
|
]
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:line}}, x, y, z)
|
@recipe function f(::Type{Val{:line}}, x, y, z)
|
||||||
@ -99,7 +112,7 @@ end
|
|||||||
@recipe function f(::Type{Val{:hline}}, x, y, z)
|
@recipe function f(::Type{Val{:hline}}, x, y, z)
|
||||||
n = length(y)
|
n = length(y)
|
||||||
newx = repeat(Float64[-1, 1, NaN], n)
|
newx = repeat(Float64[-1, 1, NaN], n)
|
||||||
newy = vec(Float64[yi for i=1:3,yi=y])
|
newy = vec(Float64[yi for i = 1:3, yi in y])
|
||||||
x := newx
|
x := newx
|
||||||
y := newy
|
y := newy
|
||||||
seriestype := :straightline
|
seriestype := :straightline
|
||||||
@ -109,7 +122,7 @@ end
|
|||||||
|
|
||||||
@recipe function f(::Type{Val{:vline}}, x, y, z)
|
@recipe function f(::Type{Val{:vline}}, x, y, z)
|
||||||
n = length(y)
|
n = length(y)
|
||||||
newx = vec(Float64[yi for i=1:3,yi=y])
|
newx = vec(Float64[yi for i = 1:3, yi in y])
|
||||||
newy = repeat(Float64[-1, 1, NaN], n)
|
newy = repeat(Float64[-1, 1, NaN], n)
|
||||||
x := newx
|
x := newx
|
||||||
y := newy
|
y := newy
|
||||||
@ -121,7 +134,7 @@ end
|
|||||||
@recipe function f(::Type{Val{:hspan}}, x, y, z)
|
@recipe function f(::Type{Val{:hspan}}, x, y, z)
|
||||||
n = div(length(y), 2)
|
n = div(length(y), 2)
|
||||||
newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
|
newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
|
||||||
newy = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...)
|
newy = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...)
|
||||||
linewidth --> 0
|
linewidth --> 0
|
||||||
x := newx
|
x := newx
|
||||||
y := newy
|
y := newy
|
||||||
@ -132,7 +145,7 @@ end
|
|||||||
|
|
||||||
@recipe function f(::Type{Val{:vspan}}, x, y, z)
|
@recipe function f(::Type{Val{:vspan}}, x, y, z)
|
||||||
n = div(length(y), 2)
|
n = div(length(y), 2)
|
||||||
newx = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...)
|
newx = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...)
|
||||||
newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
|
newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
|
||||||
linewidth --> 0
|
linewidth --> 0
|
||||||
x := newx
|
x := newx
|
||||||
@ -156,7 +169,7 @@ end
|
|||||||
primary := false
|
primary := false
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
@deps scatterpath path scatter
|
@deps scatterpath path scatter
|
||||||
|
|
||||||
@ -169,7 +182,7 @@ function make_steps(x::AbstractArray, st)
|
|||||||
n = length(x)
|
n = length(x)
|
||||||
n == 0 && return zeros(0)
|
n == 0 && return zeros(0)
|
||||||
newx = zeros(2n - 1)
|
newx = zeros(2n - 1)
|
||||||
for i in 1:n
|
for i = 1:n
|
||||||
idx = 2i - 1
|
idx = 2i - 1
|
||||||
newx[idx] = x[i]
|
newx[idx] = x[i]
|
||||||
if i > 1
|
if i > 1
|
||||||
@ -249,10 +262,10 @@ end
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
newx, newy = zeros(3n), zeros(3n)
|
newx, newy = zeros(3n), zeros(3n)
|
||||||
for i=1:n
|
for i = 1:n
|
||||||
rng = 3i-2:3i
|
rng = (3i - 2):(3i)
|
||||||
newx[rng] = [x[i], x[i], NaN]
|
newx[rng] = [x[i], x[i], NaN]
|
||||||
newy[rng] = [_cycle(fr,i), y[i], NaN]
|
newy[rng] = [_cycle(fr, i), y[i], NaN]
|
||||||
end
|
end
|
||||||
x := newx
|
x := newx
|
||||||
y := newy
|
y := newy
|
||||||
@ -282,16 +295,16 @@ end
|
|||||||
# get the value of the curve point at position t
|
# get the value of the curve point at position t
|
||||||
function bezier_value(pts::AVec, t::Real)
|
function bezier_value(pts::AVec, t::Real)
|
||||||
val = 0.0
|
val = 0.0
|
||||||
n = length(pts)-1
|
n = length(pts) - 1
|
||||||
for (i,p) in enumerate(pts)
|
for (i, p) in enumerate(pts)
|
||||||
val += p * binomial(n, i-1) * (1-t)^(n-i+1) * t^(i-1)
|
val += p * binomial(n, i - 1) * (1 - t)^(n - i + 1) * t^(i - 1)
|
||||||
end
|
end
|
||||||
val
|
val
|
||||||
end
|
end
|
||||||
|
|
||||||
# create segmented bezier curves in place of line segments
|
# create segmented bezier curves in place of line segments
|
||||||
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30)
|
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30)
|
||||||
args = z !== nothing ? (x,y,z) : (x,y)
|
args = z !== nothing ? (x, y, z) : (x, y)
|
||||||
newx, newy = zeros(0), zeros(0)
|
newx, newy = zeros(0), zeros(0)
|
||||||
fr = plotattributes[:fillrange]
|
fr = plotattributes[:fillrange]
|
||||||
newfr = fr !== nothing ? zeros(0) : nothing
|
newfr = fr !== nothing ? zeros(0) : nothing
|
||||||
@ -304,13 +317,13 @@ end
|
|||||||
for rng in iter_segments(args...)
|
for rng in iter_segments(args...)
|
||||||
length(rng) < 2 && continue
|
length(rng) < 2 && continue
|
||||||
ts = range(0, stop = 1, length = npoints)
|
ts = range(0, stop = 1, length = npoints)
|
||||||
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts))
|
nanappend!(newx, map(t -> bezier_value(_cycle(x, rng), t), ts))
|
||||||
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts))
|
nanappend!(newy, map(t -> bezier_value(_cycle(y, rng), t), ts))
|
||||||
if z !== nothing
|
if z !== nothing
|
||||||
nanappend!(newz, map(t -> bezier_value(_cycle(z,rng), t), ts))
|
nanappend!(newz, map(t -> bezier_value(_cycle(z, rng), t), ts))
|
||||||
end
|
end
|
||||||
if fr !== nothing
|
if fr !== nothing
|
||||||
nanappend!(newfr, map(t -> bezier_value(_cycle(fr,rng), t), ts))
|
nanappend!(newfr, map(t -> bezier_value(_cycle(fr, rng), t), ts))
|
||||||
end
|
end
|
||||||
# if lz !== nothing
|
# if lz !== nothing
|
||||||
# lzrng = _cycle(lz, rng) # the line_z's for this segment
|
# lzrng = _cycle(lz, rng) # the line_z's for this segment
|
||||||
@ -343,14 +356,15 @@ end
|
|||||||
|
|
||||||
# create a bar plot as a filled step function
|
# create a bar plot as a filled step function
|
||||||
@recipe function f(::Type{Val{:bar}}, x, y, z)
|
@recipe function f(::Type{Val{:bar}}, x, y, z)
|
||||||
procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y)
|
procx, procy, xscale, yscale, baseline =
|
||||||
|
_preprocess_barlike(plotattributes, x, y)
|
||||||
nx, ny = length(procx), length(procy)
|
nx, ny = length(procx), length(procy)
|
||||||
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
|
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
|
||||||
cv = [discrete_value!(axis, xi)[1] for xi=procx]
|
cv = [discrete_value!(axis, xi)[1] for xi in procx]
|
||||||
procx = if nx == ny
|
procx = if nx == ny
|
||||||
cv
|
cv
|
||||||
elseif nx == ny + 1
|
elseif nx == ny + 1
|
||||||
0.5diff(cv) + cv[1:end-1]
|
0.5 * diff(cv) + cv[1:(end - 1)]
|
||||||
else
|
else
|
||||||
error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))")
|
error("bar recipe: 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
|
end
|
||||||
@ -359,12 +373,12 @@ end
|
|||||||
bw = plotattributes[:bar_width]
|
bw = plotattributes[:bar_width]
|
||||||
hw = if bw === nothing
|
hw = if bw === nothing
|
||||||
if nx > 1
|
if nx > 1
|
||||||
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx)))
|
0.5 * _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(procx)))
|
||||||
else
|
else
|
||||||
0.5 * _bar_width
|
0.5 * _bar_width
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Float64[0.5_cycle(bw,i) for i=eachindex(procx)]
|
Float64[0.5 * _cycle(bw, i) for i in eachindex(procx)]
|
||||||
end
|
end
|
||||||
|
|
||||||
# make fillto a vector... default fills to 0
|
# make fillto a vector... default fills to 0
|
||||||
@ -378,13 +392,20 @@ end
|
|||||||
|
|
||||||
# create the bar shapes by adding x/y segments
|
# create the bar shapes by adding x/y segments
|
||||||
xseg, yseg = Segments(), Segments()
|
xseg, yseg = Segments(), Segments()
|
||||||
for i=1:ny
|
for i = 1:ny
|
||||||
yi = procy[i]
|
yi = procy[i]
|
||||||
if !isnan(yi)
|
if !isnan(yi)
|
||||||
center = procx[i]
|
center = procx[i]
|
||||||
hwi = _cycle(hw,i)
|
hwi = _cycle(hw, i)
|
||||||
fi = _cycle(fillto,i)
|
fi = _cycle(fillto, i)
|
||||||
push!(xseg, center-hwi, center-hwi, center+hwi, center+hwi, center-hwi)
|
push!(
|
||||||
|
xseg,
|
||||||
|
center - hwi,
|
||||||
|
center - hwi,
|
||||||
|
center + hwi,
|
||||||
|
center + hwi,
|
||||||
|
center - hwi,
|
||||||
|
)
|
||||||
push!(yseg, yi, fi, fi, yi, yi)
|
push!(yseg, yi, fi, fi, yi, yi)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -415,8 +436,8 @@ end
|
|||||||
m, n = size(z.surf)
|
m, n = size(z.surf)
|
||||||
x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n)
|
x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n)
|
||||||
fz = zeros(m * n)
|
fz = zeros(m * n)
|
||||||
for i in 1:m # y
|
for i = 1:m # y
|
||||||
for j in 1:n # x
|
for j = 1:n # x
|
||||||
k = (j - 1) * m + i
|
k = (j - 1) * m + i
|
||||||
inds = (6 * (k - 1) + 1):(6 * k - 1)
|
inds = (6 * (k - 1) + 1):(6 * k - 1)
|
||||||
x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]]
|
x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]]
|
||||||
@ -440,13 +461,17 @@ end
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Histograms
|
# Histograms
|
||||||
|
|
||||||
_bin_centers(v::AVec) = (v[1:end-1] + v[2:end]) / 2
|
_bin_centers(v::AVec) = (v[1:(end - 1)] + v[2:end]) / 2
|
||||||
|
|
||||||
_is_positive(x) = (x > 0) && !(x ≈ 0)
|
_is_positive(x) = (x > 0) && !(x ≈ 0)
|
||||||
|
|
||||||
_positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN)
|
_positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN)
|
||||||
|
|
||||||
function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) where T<:AbstractFloat
|
function _scale_adjusted_values(
|
||||||
|
::Type{T},
|
||||||
|
V::AbstractVector,
|
||||||
|
scale::Symbol,
|
||||||
|
) where {T<:AbstractFloat}
|
||||||
if scale in _logScales
|
if scale in _logScales
|
||||||
[_positive_else_nan(T, x) for x in V]
|
[_positive_else_nan(T, x) for x in V]
|
||||||
else
|
else
|
||||||
@ -455,7 +480,7 @@ function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) whe
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real
|
function _binbarlike_baseline(min_value::T, scale::Symbol) where {T<:Real}
|
||||||
if (scale in _logScales)
|
if (scale in _logScales)
|
||||||
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
|
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
|
||||||
else
|
else
|
||||||
@ -464,7 +489,11 @@ function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:AbstractFloat
|
function _preprocess_binbarlike_weights(
|
||||||
|
::Type{T},
|
||||||
|
w,
|
||||||
|
wscale::Symbol,
|
||||||
|
) where {T<:AbstractFloat}
|
||||||
w_adj = _scale_adjusted_values(T, w, wscale)
|
w_adj = _scale_adjusted_values(T, w, wscale)
|
||||||
w_min = ignorenan_minimum(w_adj)
|
w_min = ignorenan_minimum(w_adj)
|
||||||
w_max = ignorenan_maximum(w_adj)
|
w_max = ignorenan_maximum(w_adj)
|
||||||
@ -490,7 +519,8 @@ end
|
|||||||
|
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:barbins}}, x, y, z)
|
@recipe function f(::Type{Val{:barbins}}, x, y, z)
|
||||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
|
edge, weights, xscale, yscale, baseline =
|
||||||
|
_preprocess_binlike(plotattributes, x, y)
|
||||||
if (plotattributes[:bar_width] === nothing)
|
if (plotattributes[:bar_width] === nothing)
|
||||||
bar_width := diff(edge)
|
bar_width := diff(edge)
|
||||||
end
|
end
|
||||||
@ -503,8 +533,9 @@ end
|
|||||||
|
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
|
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
|
||||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
|
edge, weights, xscale, yscale, baseline =
|
||||||
xerror := diff(edge)/2
|
_preprocess_binlike(plotattributes, x, y)
|
||||||
|
xerror := diff(edge) / 2
|
||||||
x := _bin_centers(edge)
|
x := _bin_centers(edge)
|
||||||
y := weights
|
y := weights
|
||||||
seriestype := :scatter
|
seriestype := :scatter
|
||||||
@ -513,7 +544,13 @@ end
|
|||||||
@deps scatterbins scatter
|
@deps scatterbins scatter
|
||||||
|
|
||||||
|
|
||||||
function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::Symbol)
|
function _stepbins_path(
|
||||||
|
edge,
|
||||||
|
weights,
|
||||||
|
baseline::Real,
|
||||||
|
xscale::Symbol,
|
||||||
|
yscale::Symbol,
|
||||||
|
)
|
||||||
log_scale_x = xscale in _logScales
|
log_scale_x = xscale in _logScales
|
||||||
log_scale_y = yscale in _logScales
|
log_scale_y = yscale in _logScales
|
||||||
|
|
||||||
@ -538,7 +575,7 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
|
|||||||
w, it_state_w = it_tuple_w
|
w, it_state_w = it_tuple_w
|
||||||
|
|
||||||
if (log_scale_x && a ≈ 0)
|
if (log_scale_x && a ≈ 0)
|
||||||
a = oftype(a, b/_logScaleBases[xscale]^3)
|
a = oftype(a, b / _logScaleBases[xscale]^3)
|
||||||
end
|
end
|
||||||
|
|
||||||
if isnan(w)
|
if isnan(w)
|
||||||
@ -575,9 +612,11 @@ end
|
|||||||
|
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
|
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
|
||||||
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
|
axis =
|
||||||
|
plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
|
||||||
|
|
||||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
|
edge, weights, xscale, yscale, baseline =
|
||||||
|
_preprocess_binlike(plotattributes, x, y)
|
||||||
|
|
||||||
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
|
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
|
||||||
if !isvertical(plotattributes)
|
if !isvertical(plotattributes)
|
||||||
@ -607,9 +646,19 @@ end
|
|||||||
end
|
end
|
||||||
Plots.@deps stepbins path
|
Plots.@deps stepbins path
|
||||||
|
|
||||||
wand_edges(x...) = (@warn("Load the StatsPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
wand_edges(x...) = (
|
||||||
|
@warn(
|
||||||
|
"Load the StatsPlots package in order to use :wand bins. Defaulting to :auto",
|
||||||
|
once = true
|
||||||
|
);
|
||||||
|
:auto
|
||||||
|
)
|
||||||
|
|
||||||
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
|
function _auto_binning_nbins(
|
||||||
|
vs::NTuple{N,AbstractVector},
|
||||||
|
dim::Integer;
|
||||||
|
mode::Symbol = :auto,
|
||||||
|
) where {N}
|
||||||
max_bins = 10_000
|
max_bins = 10_000
|
||||||
_cl(x) = min(ceil(Int, max(x, one(x))), max_bins)
|
_cl(x) = min(ceil(Int, max(x, one(x))), max_bins)
|
||||||
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
|
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
|
||||||
@ -618,8 +667,13 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
|
|||||||
n_samples = length(LinearIndices(first(vs)))
|
n_samples = length(LinearIndices(first(vs)))
|
||||||
|
|
||||||
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
|
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
|
||||||
nd = n_samples^(1/(2+N))
|
nd = n_samples^(1 / (2 + N))
|
||||||
nd = N == 2 ? min(n_samples^(1/(2+N)), nd / (1-cor(first(vs), last(vs))^2)^(3//8)) : nd # the >2-dimensional case does not have a nice solution to correlations
|
nd = N == 2 ?
|
||||||
|
min(
|
||||||
|
n_samples^(1 / (2 + N)),
|
||||||
|
nd / (1 - cor(first(vs), last(vs))^2)^(3 // 8),
|
||||||
|
) :
|
||||||
|
nd # the >2-dimensional case does not have a nice solution to correlations
|
||||||
|
|
||||||
v = vs[dim]
|
v = vs[dim]
|
||||||
|
|
||||||
@ -644,32 +698,52 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} = StatsBase.histrange(vs[dim], binning, :left)
|
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} =
|
||||||
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
|
StatsBase.histrange(vs[dim], binning, :left)
|
||||||
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
|
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} =
|
||||||
|
_hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
|
||||||
|
_hist_edge(
|
||||||
|
vs::NTuple{N,AbstractVector},
|
||||||
|
dim::Integer,
|
||||||
|
binning::AbstractVector,
|
||||||
|
) where {N} = binning
|
||||||
|
|
||||||
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N, Any}) where {N} =
|
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N,Any}) where {N} =
|
||||||
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
|
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
|
||||||
|
|
||||||
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
|
_hist_edges(
|
||||||
map(dim -> _hist_edge(vs, dim, binning), (1:N...,))
|
vs::NTuple{N,AbstractVector},
|
||||||
|
binning::Union{Integer,Symbol,AbstractVector},
|
||||||
|
) where {N} = map(dim -> _hist_edge(vs, dim, binning), (1:N...,))
|
||||||
|
|
||||||
_hist_norm_mode(mode::Symbol) = mode
|
_hist_norm_mode(mode::Symbol) = mode
|
||||||
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
|
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
|
||||||
|
|
||||||
_filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs)
|
_filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs)
|
||||||
function _filternans(vs::NTuple{N,AbstractVector}) where N
|
function _filternans(vs::NTuple{N,AbstractVector}) where {N}
|
||||||
_invertedindex(v, not) = [j for (i,j) in enumerate(v) if !(i ∈ not)]
|
_invertedindex(v, not) = [j for (i, j) in enumerate(v) if !(i ∈ not)]
|
||||||
nots = union(Set.(findall.(!isfinite, vs))...)
|
nots = union(Set.(findall.(!isfinite, vs))...)
|
||||||
_invertedindex.(vs, Ref(nots))
|
_invertedindex.(vs, Ref(nots))
|
||||||
end
|
end
|
||||||
|
|
||||||
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
|
function _make_hist(
|
||||||
|
vs::NTuple{N,AbstractVector},
|
||||||
|
binning;
|
||||||
|
normed = false,
|
||||||
|
weights = nothing,
|
||||||
|
) where {N}
|
||||||
localvs = _filternans(vs)
|
localvs = _filternans(vs)
|
||||||
edges = _hist_edges(localvs, binning)
|
edges = _hist_edges(localvs, binning)
|
||||||
h = float( weights === nothing ?
|
h = float(
|
||||||
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
|
weights === nothing ?
|
||||||
StatsBase.fit(StatsBase.Histogram, localvs, StatsBase.Weights(weights), edges, closed = :left)
|
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
|
||||||
|
StatsBase.fit(
|
||||||
|
StatsBase.Histogram,
|
||||||
|
localvs,
|
||||||
|
StatsBase.Weights(weights),
|
||||||
|
edges,
|
||||||
|
closed = :left,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
normalize!(h, mode = _hist_norm_mode(normed))
|
normalize!(h, mode = _hist_norm_mode(normed))
|
||||||
end
|
end
|
||||||
@ -682,7 +756,12 @@ end
|
|||||||
@deps histogram barhist
|
@deps histogram barhist
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:barhist}}, x, y, z)
|
@recipe function f(::Type{Val{:barhist}}, x, y, z)
|
||||||
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
h = _make_hist(
|
||||||
|
(y,),
|
||||||
|
plotattributes[:bins],
|
||||||
|
normed = plotattributes[:normalize],
|
||||||
|
weights = plotattributes[:weights],
|
||||||
|
)
|
||||||
x := h.edges[1]
|
x := h.edges[1]
|
||||||
y := h.weights
|
y := h.weights
|
||||||
seriestype := :barbins
|
seriestype := :barbins
|
||||||
@ -691,7 +770,12 @@ end
|
|||||||
@deps barhist barbins
|
@deps barhist barbins
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:stephist}}, x, y, z)
|
@recipe function f(::Type{Val{:stephist}}, x, y, z)
|
||||||
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
h = _make_hist(
|
||||||
|
(y,),
|
||||||
|
plotattributes[:bins],
|
||||||
|
normed = plotattributes[:normalize],
|
||||||
|
weights = plotattributes[:weights],
|
||||||
|
)
|
||||||
x := h.edges[1]
|
x := h.edges[1]
|
||||||
y := h.weights
|
y := h.weights
|
||||||
seriestype := :stepbins
|
seriestype := :stepbins
|
||||||
@ -700,7 +784,12 @@ end
|
|||||||
@deps stephist stepbins
|
@deps stephist stepbins
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:scatterhist}}, x, y, z)
|
@recipe function f(::Type{Val{:scatterhist}}, x, y, z)
|
||||||
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
h = _make_hist(
|
||||||
|
(y,),
|
||||||
|
plotattributes[:bins],
|
||||||
|
normed = plotattributes[:normalize],
|
||||||
|
weights = plotattributes[:weights],
|
||||||
|
)
|
||||||
x := h.edges[1]
|
x := h.edges[1]
|
||||||
y := h.weights
|
y := h.weights
|
||||||
seriestype := :scatterbins
|
seriestype := :scatterbins
|
||||||
@ -709,19 +798,23 @@ end
|
|||||||
@deps scatterhist scatterbins
|
@deps scatterhist scatterbins
|
||||||
|
|
||||||
|
|
||||||
@recipe function f(h::StatsBase.Histogram{T, 1, E}) where {T, E}
|
@recipe function f(h::StatsBase.Histogram{T,1,E}) where {T,E}
|
||||||
seriestype --> :barbins
|
seriestype --> :barbins
|
||||||
|
|
||||||
st_map = Dict(
|
st_map = Dict(
|
||||||
:bar => :barbins, :scatter => :scatterbins, :step => :stepbins,
|
:bar => :barbins,
|
||||||
:steppost => :stepbins # :step can be mapped to :steppost in pre-processing
|
:scatter => :scatterbins,
|
||||||
|
:step => :stepbins,
|
||||||
|
:steppost => :stepbins, # :step can be mapped to :steppost in pre-processing
|
||||||
)
|
)
|
||||||
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
|
seriestype :=
|
||||||
|
get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
|
||||||
|
|
||||||
if plotattributes[:seriestype] == :scatterbins
|
if plotattributes[:seriestype] == :scatterbins
|
||||||
# Workaround, error bars currently not set correctly by scatterbins
|
# Workaround, error bars currently not set correctly by scatterbins
|
||||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, h.edges[1], h.weights)
|
edge, weights, xscale, yscale, baseline =
|
||||||
xerror --> diff(h.edges[1])/2
|
_preprocess_binlike(plotattributes, h.edges[1], h.weights)
|
||||||
|
xerror --> diff(h.edges[1]) / 2
|
||||||
seriestype := :scatter
|
seriestype := :scatter
|
||||||
(Plots._bin_centers(edge), weights)
|
(Plots._bin_centers(edge), weights)
|
||||||
else
|
else
|
||||||
@ -730,7 +823,7 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@recipe function f(hv::AbstractVector{H}) where H <: StatsBase.Histogram
|
@recipe function f(hv::AbstractVector{H}) where {H<:StatsBase.Histogram}
|
||||||
for h in hv
|
for h in hv
|
||||||
@series begin
|
@series begin
|
||||||
h
|
h
|
||||||
@ -769,7 +862,12 @@ Plots.@deps bins2d heatmap
|
|||||||
|
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
|
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
|
||||||
h = _make_hist((x, y), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
h = _make_hist(
|
||||||
|
(x, y),
|
||||||
|
plotattributes[:bins],
|
||||||
|
normed = plotattributes[:normalize],
|
||||||
|
weights = plotattributes[:weights],
|
||||||
|
)
|
||||||
x := h.edges[1]
|
x := h.edges[1]
|
||||||
y := h.edges[2]
|
y := h.edges[2]
|
||||||
z := Surface(h.weights)
|
z := Surface(h.weights)
|
||||||
@ -779,7 +877,7 @@ end
|
|||||||
@deps histogram2d bins2d
|
@deps histogram2d bins2d
|
||||||
|
|
||||||
|
|
||||||
@recipe function f(h::StatsBase.Histogram{T, 2, E}) where {T, E}
|
@recipe function f(h::StatsBase.Histogram{T,2,E}) where {T,E}
|
||||||
seriestype --> :bins2d
|
seriestype --> :bins2d
|
||||||
(h.edges[1], h.edges[2], Surface(h.weights))
|
(h.edges[1], h.edges[2], Surface(h.weights))
|
||||||
end
|
end
|
||||||
@ -801,6 +899,91 @@ end
|
|||||||
# note: don't add dependencies because this really isn't a drop-in replacement
|
# note: don't add dependencies because this really isn't a drop-in replacement
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# lens! - magnify a region of a plot
|
||||||
|
lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...)
|
||||||
|
export lens!
|
||||||
|
@recipe function f(::Type{Val{:lens}}, plt::AbstractPlot)
|
||||||
|
sp_index, inset_bbox = plotattributes[:inset_subplots]
|
||||||
|
if !(width(inset_bbox) isa Measures.Length{:w,<:Real})
|
||||||
|
throw(ArgumentError("Inset bounding box needs to in relative coordinates."))
|
||||||
|
end
|
||||||
|
sp = plt.subplots[sp_index]
|
||||||
|
xl1, xl2 = xlims(plt.subplots[sp_index])
|
||||||
|
bbx1 = xl1 + left(inset_bbox).value * (xl2 - xl1)
|
||||||
|
bbx2 = bbx1 + width(inset_bbox).value * (xl2 - xl1)
|
||||||
|
yl1, yl2 = ylims(plt.subplots[sp_index])
|
||||||
|
bby1 = yl1 + (1 - bottom(inset_bbox).value) * (yl2 - yl1)
|
||||||
|
bby2 = bby1 + height(inset_bbox).value * (yl2 - yl1)
|
||||||
|
bbx = bbx1 + width(inset_bbox).value * (xl2 - xl1) / 2
|
||||||
|
bby = bby1 + height(inset_bbox).value * (yl2 - yl1) / 2
|
||||||
|
lens_index = last(plt.subplots)[:subplot_index] + 1
|
||||||
|
x1, x2 = plotattributes[:x]
|
||||||
|
y1, y2 = plotattributes[:y]
|
||||||
|
seriestype := :path
|
||||||
|
label := ""
|
||||||
|
linecolor := :lightgray
|
||||||
|
bbx_mag = (x1 + x2) / 2
|
||||||
|
bby_mag = (y1 + y2) / 2
|
||||||
|
xi_lens, yi_lens = intersection_point(bbx_mag, bby_mag, bbx, bby, abs(bby2 - bby1), abs(bbx2 - bbx1))
|
||||||
|
xi_mag, yi_mag = intersection_point(bbx, bby, bbx_mag, bby_mag, abs(y2 - y1), abs(x2 - x1))
|
||||||
|
# add lines
|
||||||
|
if xl1 < xi_lens < xl2 &&
|
||||||
|
yl1 < yi_lens < yl2
|
||||||
|
@series begin
|
||||||
|
subplot := sp_index
|
||||||
|
x := [xi_mag, xi_lens]
|
||||||
|
y := [yi_mag, yi_lens]
|
||||||
|
()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# add magnification shape
|
||||||
|
@series begin
|
||||||
|
subplot := sp_index
|
||||||
|
x := [x1, x1, x2, x2, x1]
|
||||||
|
y := [y1, y2, y2, y1, y1]
|
||||||
|
()
|
||||||
|
end
|
||||||
|
# add subplot
|
||||||
|
for series in sp.series_list
|
||||||
|
@series begin
|
||||||
|
plotattributes = merge(plotattributes, copy(series.plotattributes))
|
||||||
|
subplot := lens_index
|
||||||
|
label := ""
|
||||||
|
xlims := (x1, x2)
|
||||||
|
ylims := (y1, y2)
|
||||||
|
()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
backup = copy(plotattributes)
|
||||||
|
empty!(plotattributes)
|
||||||
|
seriestype := :path
|
||||||
|
series_plotindex := backup[:series_plotindex]
|
||||||
|
end
|
||||||
|
|
||||||
|
function intersection_point(xA, yA, xB, yB, h, w)
|
||||||
|
s = (yA - yB) / (xA - xB)
|
||||||
|
hh = h / 2
|
||||||
|
hw = w / 2
|
||||||
|
# left or right?
|
||||||
|
if -hh <= s * hw <= hh
|
||||||
|
if xA > xB
|
||||||
|
# right
|
||||||
|
return xB + hw, yB + s * hw
|
||||||
|
else # left
|
||||||
|
return xB - hw, yB - s * hw
|
||||||
|
end
|
||||||
|
# top or bot?
|
||||||
|
elseif -hw <= hh/s <= hw
|
||||||
|
if yA > yB
|
||||||
|
# top
|
||||||
|
return xB + hh/s, yB + hh
|
||||||
|
else
|
||||||
|
# bottom
|
||||||
|
return xB - hh/s, yB - hh
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# contourf - filled contours
|
# contourf - filled contours
|
||||||
|
|
||||||
@ -855,7 +1038,11 @@ end
|
|||||||
@recipe function f(::Type{Val{:yerror}}, x, y, z)
|
@recipe function f(::Type{Val{:yerror}}, x, y, z)
|
||||||
error_style!(plotattributes)
|
error_style!(plotattributes)
|
||||||
markershape := :hline
|
markershape := :hline
|
||||||
plotattributes[:x], plotattributes[:y] = error_coords(plotattributes[:x], plotattributes[:y], error_zipit(plotattributes[:yerror]))
|
plotattributes[:x], plotattributes[:y] = error_coords(
|
||||||
|
plotattributes[:x],
|
||||||
|
plotattributes[:y],
|
||||||
|
error_zipit(plotattributes[:yerror]),
|
||||||
|
)
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
@deps yerror path
|
@deps yerror path
|
||||||
@ -863,7 +1050,11 @@ end
|
|||||||
@recipe function f(::Type{Val{:xerror}}, x, y, z)
|
@recipe function f(::Type{Val{:xerror}}, x, y, z)
|
||||||
error_style!(plotattributes)
|
error_style!(plotattributes)
|
||||||
markershape := :vline
|
markershape := :vline
|
||||||
plotattributes[:y], plotattributes[:x] = error_coords(plotattributes[:y], plotattributes[:x], error_zipit(plotattributes[:xerror]))
|
plotattributes[:y], plotattributes[:x] = error_coords(
|
||||||
|
plotattributes[:y],
|
||||||
|
plotattributes[:x],
|
||||||
|
error_zipit(plotattributes[:xerror]),
|
||||||
|
)
|
||||||
()
|
()
|
||||||
end
|
end
|
||||||
@deps xerror path
|
@deps xerror path
|
||||||
@ -898,15 +1089,15 @@ function quiver_using_arrows(plotattributes::AKW)
|
|||||||
first(vi), last(vi)
|
first(vi), last(vi)
|
||||||
elseif isscalar(vi)
|
elseif isscalar(vi)
|
||||||
vi, vi
|
vi, vi
|
||||||
elseif isa(vi,Function)
|
elseif isa(vi, Function)
|
||||||
vi(xi, yi)
|
vi(xi, yi)
|
||||||
else
|
else
|
||||||
error("unexpected vi type $(typeof(vi)) for quiver: $vi")
|
error("unexpected vi type $(typeof(vi)) for quiver: $vi")
|
||||||
end
|
end
|
||||||
|
|
||||||
# add the points
|
# add the points
|
||||||
nanappend!(x, [xi, xi+vx, NaN])
|
nanappend!(x, [xi, xi + vx, NaN])
|
||||||
nanappend!(y, [yi, yi+vy, NaN])
|
nanappend!(y, [yi, yi + vy, NaN])
|
||||||
end
|
end
|
||||||
|
|
||||||
plotattributes[:x], plotattributes[:y] = x, y
|
plotattributes[:x], plotattributes[:y] = x, y
|
||||||
@ -936,7 +1127,7 @@ function quiver_using_hack(plotattributes::AKW)
|
|||||||
first(vi), last(vi)
|
first(vi), last(vi)
|
||||||
elseif isscalar(vi)
|
elseif isscalar(vi)
|
||||||
vi, vi
|
vi, vi
|
||||||
elseif isa(vi,Function)
|
elseif isa(vi, Function)
|
||||||
vi(xi, yi)
|
vi(xi, yi)
|
||||||
else
|
else
|
||||||
error("unexpected vi type $(typeof(vi)) for quiver: $vi")
|
error("unexpected vi type $(typeof(vi)) for quiver: $vi")
|
||||||
@ -951,8 +1142,11 @@ function quiver_using_hack(plotattributes::AKW)
|
|||||||
U1 *= arrow_h
|
U1 *= arrow_h
|
||||||
U2 *= arrow_w
|
U2 *= arrow_w
|
||||||
|
|
||||||
ppv = p+v
|
ppv = p + v
|
||||||
nanappend!(pts, P2[p, ppv-U1, ppv-U1+U2, ppv, ppv-U1-U2, ppv-U1])
|
nanappend!(
|
||||||
|
pts,
|
||||||
|
P2[p, ppv - U1, ppv - U1 + U2, ppv, ppv - U1 - U2, ppv - U1],
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
plotattributes[:x], plotattributes[:y] = Plots.unzip(pts[2:end])
|
plotattributes[:x], plotattributes[:y] = Plots.unzip(pts[2:end])
|
||||||
@ -977,32 +1171,28 @@ end
|
|||||||
|
|
||||||
"Represent Open High Low Close data (used in finance)"
|
"Represent Open High Low Close data (used in finance)"
|
||||||
mutable struct OHLC{T<:Real}
|
mutable struct OHLC{T<:Real}
|
||||||
open::T
|
open::T
|
||||||
high::T
|
high::T
|
||||||
low::T
|
low::T
|
||||||
close::T
|
close::T
|
||||||
end
|
end
|
||||||
Base.convert(::Type{OHLC}, tup::Tuple) = OHLC(tup...)
|
Base.convert(::Type{OHLC}, tup::Tuple) = OHLC(tup...)
|
||||||
# Base.tuple(ohlc::OHLC) = (ohlc.open, ohlc.high, ohlc.low, ohlc.close)
|
# Base.tuple(ohlc::OHLC) = (ohlc.open, ohlc.high, ohlc.low, ohlc.close)
|
||||||
|
|
||||||
# get one OHLC path
|
# get one OHLC path
|
||||||
function get_xy(o::OHLC, x, xdiff)
|
function get_xy(o::OHLC, x, xdiff)
|
||||||
xl, xm, xr = x-xdiff, x, x+xdiff
|
xl, xm, xr = x - xdiff, x, x + xdiff
|
||||||
ox = [xl, xm, NaN,
|
ox = [xl, xm, NaN, xm, xm, NaN, xm, xr]
|
||||||
xm, xm, NaN,
|
oy = [o.open, o.open, NaN, o.low, o.high, NaN, o.close, o.close]
|
||||||
xm, xr]
|
|
||||||
oy = [o.open, o.open, NaN,
|
|
||||||
o.low, o.high, NaN,
|
|
||||||
o.close, o.close]
|
|
||||||
ox, oy
|
ox, oy
|
||||||
end
|
end
|
||||||
|
|
||||||
# get the joined vector
|
# get the joined vector
|
||||||
function get_xy(v::AVec{OHLC}, x = eachindex(v))
|
function get_xy(v::AVec{OHLC}, x = eachindex(v))
|
||||||
xdiff = 0.3ignorenan_mean(abs.(diff(x)))
|
xdiff = 0.3 * ignorenan_mean(abs.(diff(x)))
|
||||||
x_out, y_out = zeros(0), zeros(0)
|
x_out, y_out = zeros(0), zeros(0)
|
||||||
for (i,ohlc) in enumerate(v)
|
for (i, ohlc) in enumerate(v)
|
||||||
ox,oy = get_xy(ohlc, x[i], xdiff)
|
ox, oy = get_xy(ohlc, x[i], xdiff)
|
||||||
nanappend!(x_out, ox)
|
nanappend!(x_out, ox)
|
||||||
nanappend!(y_out, oy)
|
nanappend!(y_out, oy)
|
||||||
end
|
end
|
||||||
@ -1015,10 +1205,17 @@ end
|
|||||||
|
|
||||||
# to squash ambiguity warnings...
|
# to squash ambiguity warnings...
|
||||||
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
|
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
|
||||||
@recipe f(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error()
|
@recipe f(
|
||||||
|
x::AVec{Function},
|
||||||
|
v::AVec{Tuple{R1,R2,R3,R4}},
|
||||||
|
) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error()
|
||||||
|
|
||||||
# this must be OHLC?
|
# this must be OHLC?
|
||||||
@recipe f(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc]
|
@recipe f(
|
||||||
|
x::AVec,
|
||||||
|
ohlc::AVec{Tuple{R1,R2,R3,R4}},
|
||||||
|
) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} =
|
||||||
|
x, OHLC[OHLC(t...) for t in ohlc]
|
||||||
|
|
||||||
@recipe function f(x::AVec, v::AVec{OHLC})
|
@recipe function f(x::AVec, v::AVec{OHLC})
|
||||||
seriestype := :path
|
seriestype := :path
|
||||||
@ -1056,11 +1253,11 @@ end
|
|||||||
@assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix
|
@assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix
|
||||||
seriestype := :spy
|
seriestype := :spy
|
||||||
mat = g.args[1]
|
mat = g.args[1]
|
||||||
n,m = axes(mat)
|
n, m = axes(mat)
|
||||||
Plots.SliceIt, m, n, Surface(mat)
|
Plots.SliceIt, m, n, Surface(mat)
|
||||||
end
|
end
|
||||||
|
|
||||||
@recipe function f(::Type{Val{:spy}}, x,y,z)
|
@recipe function f(::Type{Val{:spy}}, x, y, z)
|
||||||
yflip := true
|
yflip := true
|
||||||
aspect_ratio := 1
|
aspect_ratio := 1
|
||||||
rs, cs, zs = findnz(z.surf)
|
rs, cs, zs = findnz(z.surf)
|
||||||
@ -1086,7 +1283,8 @@ end
|
|||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
|
|
||||||
"Adds ax+b... straight line over the current plot, without changing the axis limits"
|
"Adds ax+b... straight line over the current plot, without changing the axis limits"
|
||||||
abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...)
|
abline!(plt::Plot, a, b; kw...) =
|
||||||
|
plot!(plt, [0, 1], [b, b + a]; seriestype = :straightline, kw...)
|
||||||
|
|
||||||
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||||
|
|
||||||
@ -1099,9 +1297,11 @@ datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
|
|||||||
timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
|
timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
|
||||||
|
|
||||||
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
|
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
|
||||||
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
|
@recipe f(::Type{DateTime}, dt::DateTime) =
|
||||||
|
(dt -> Dates.value(dt), datetimeformatter)
|
||||||
@recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter)
|
@recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter)
|
||||||
@recipe f(::Type{P}, t::P) where P <: Dates.Period = (t -> Dates.value(t), t -> string(P(t)))
|
@recipe f(::Type{P}, t::P) where {P<:Dates.Period} =
|
||||||
|
(t -> Dates.value(t), t -> string(P(t)))
|
||||||
|
|
||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
# Characters
|
# Characters
|
||||||
@ -1111,7 +1311,7 @@ timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
|
|||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
# Complex Numbers
|
# Complex Numbers
|
||||||
|
|
||||||
@recipe function f(A::Array{Complex{T}}) where T<:Number
|
@recipe function f(A::Array{Complex{T}}) where {T<:Number}
|
||||||
xguide --> "Re(x)"
|
xguide --> "Re(x)"
|
||||||
yguide --> "Im(x)"
|
yguide --> "Im(x)"
|
||||||
real.(A), imag.(A)
|
real.(A), imag.(A)
|
||||||
@ -1120,10 +1320,10 @@ end
|
|||||||
# Splits a complex matrix to its real and complex parts
|
# Splits a complex matrix to its real and complex parts
|
||||||
# Reals defaults solid, imaginary defaults dashed
|
# Reals defaults solid, imaginary defaults dashed
|
||||||
# Label defaults are changed to match the real-imaginary reference / indexing
|
# Label defaults are changed to match the real-imaginary reference / indexing
|
||||||
@recipe function f(x::AbstractArray{T},y::Array{Complex{T2}}) where {T<:Real,T2}
|
@recipe function f(x::AbstractArray{T}, y::Array{Complex{T2}}) where {T<:Real,T2}
|
||||||
ylabel --> "Re(y)"
|
ylabel --> "Re(y)"
|
||||||
zlabel --> "Im(y)"
|
zlabel --> "Im(y)"
|
||||||
x,real.(y),imag.(y)
|
x, real.(y), imag.(y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -1137,7 +1337,7 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
library = PlotUtils.color_libraries[cl.args[1]]
|
library = PlotUtils.color_libraries[cl.args[1]]
|
||||||
z = sqrt.((1:15)*reshape(1:20,1,:))
|
z = sqrt.((1:15) * reshape(1:20, 1, :))
|
||||||
|
|
||||||
seriestype := :heatmap
|
seriestype := :heatmap
|
||||||
ticks := nothing
|
ticks := nothing
|
||||||
@ -1161,7 +1361,7 @@ end
|
|||||||
if !(length(grad.args) == 1 && isa(grad.args[1], Symbol))
|
if !(length(grad.args) == 1 && isa(grad.args[1], Symbol))
|
||||||
error("showgradient takes the name of a color gradient as a Symbol")
|
error("showgradient takes the name of a color gradient as a Symbol")
|
||||||
end
|
end
|
||||||
z = sqrt.((1:15)*reshape(1:20,1,:))
|
z = sqrt.((1:15) * reshape(1:20, 1, :))
|
||||||
seriestype := :heatmap
|
seriestype := :heatmap
|
||||||
ticks := nothing
|
ticks := nothing
|
||||||
legend := false
|
legend := false
|
||||||
@ -1184,9 +1384,9 @@ end
|
|||||||
weights = cumsum(weights, dims = 2)
|
weights = cumsum(weights, dims = 2)
|
||||||
seriestype := :shape
|
seriestype := :shape
|
||||||
|
|
||||||
# create a filled polygon for each item
|
# create a filled polygon for each item
|
||||||
for c=axes(weights,2)
|
for c in axes(weights, 2)
|
||||||
sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1]))
|
sx = vcat(weights[:, c], c == 1 ? zeros(n) : reverse(weights[:, c - 1]))
|
||||||
sy = vcat(returns, reverse(returns))
|
sy = vcat(returns, reverse(returns))
|
||||||
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
|
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
|
||||||
end
|
end
|
||||||
@ -1205,13 +1405,13 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f
|
|||||||
@userplot AreaPlot
|
@userplot AreaPlot
|
||||||
|
|
||||||
@recipe function f(a::AreaPlot)
|
@recipe function f(a::AreaPlot)
|
||||||
data = cumsum(a.args[end], dims=2)
|
data = cumsum(a.args[end], dims = 2)
|
||||||
x = length(a.args) == 1 ? (axes(data, 1)) : a.args[1]
|
x = length(a.args) == 1 ? (axes(data, 1)) : a.args[1]
|
||||||
seriestype := :line
|
seriestype := :line
|
||||||
for i in axes(data, 2)
|
for i in axes(data, 2)
|
||||||
@series begin
|
@series begin
|
||||||
fillrange := i > 1 ? data[:,i-1] : 0
|
fillrange := i > 1 ? data[:, i - 1] : 0
|
||||||
x, data[:,i]
|
x, data[:, i]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -347,6 +347,7 @@ end
|
|||||||
seriestype := :heatmap
|
seriestype := :heatmap
|
||||||
yflip --> true
|
yflip --> true
|
||||||
cbar --> false
|
cbar --> false
|
||||||
|
aspect_ratio --> :equal
|
||||||
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
|
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
|
||||||
SliceIt, m, n, Surface(z)
|
SliceIt, m, n, Surface(z)
|
||||||
end
|
end
|
||||||
|
|||||||
30
src/utils.jl
30
src/utils.jl
@ -116,24 +116,11 @@ end
|
|||||||
|
|
||||||
function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
|
function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
|
||||||
n, m = size(z)
|
n, m = size(z)
|
||||||
# idx = 0
|
|
||||||
colors = ColorGradient(vec(z))
|
colors = ColorGradient(vec(z))
|
||||||
newz = reshape(range(0, stop=1, length=n*m), n, m)
|
newz = reshape(range(0, stop=1, length=n*m), n, m)
|
||||||
newz, colors
|
newz, colors
|
||||||
# newz = zeros(n, m)
|
|
||||||
# for i=1:n, j=1:m
|
|
||||||
# push!(colors, T(z[i,j]...))
|
|
||||||
# newz[i,j] = idx / (n*m-1)
|
|
||||||
# idx += 1
|
|
||||||
# end
|
|
||||||
# newz, ColorGradient(colors)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function imageHack(plotattributes::AKW)
|
|
||||||
is_seriestype_supported(:heatmap) || error("Neither :image or :heatmap are supported!")
|
|
||||||
plotattributes[:seriestype] = :heatmap
|
|
||||||
plotattributes[:z], plotattributes[:fillcolor] = replace_image_with_heatmap(plotattributes[:z].surf)
|
|
||||||
end
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
"Build line segments for plotting"
|
"Build line segments for plotting"
|
||||||
@ -693,6 +680,10 @@ function get_markerstrokealpha(series, i::Int = 1)
|
|||||||
_cycle(series[:markerstrokealpha], i)
|
_cycle(series[:markerstrokealpha], i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_markerstrokewidth(series, i::Int = 1)
|
||||||
|
_cycle(series[:markerstrokewidth], i)
|
||||||
|
end
|
||||||
|
|
||||||
function has_attribute_segments(series::Series)
|
function has_attribute_segments(series::Series)
|
||||||
# we want to check if a series needs to be split into segments just because
|
# we want to check if a series needs to be split into segments just because
|
||||||
# of its attributes
|
# of its attributes
|
||||||
@ -706,6 +697,19 @@ function has_attribute_segments(series::Series)
|
|||||||
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :linestyle, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z))
|
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :linestyle, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_aspect_ratio(sp)
|
||||||
|
aspect_ratio = sp[:aspect_ratio]
|
||||||
|
if aspect_ratio == :auto
|
||||||
|
aspect_ratio = :none
|
||||||
|
for series in series_list(sp)
|
||||||
|
if series[:seriestype] == :image
|
||||||
|
aspect_ratio = :equal
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return aspect_ratio
|
||||||
|
end
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
makekw(; kw...) = KW(kw)
|
makekw(; kw...) = KW(kw)
|
||||||
|
|||||||
@ -42,7 +42,31 @@ include("imgcomp.jl")
|
|||||||
Random.seed!(1234)
|
Random.seed!(1234)
|
||||||
default(show=false, reuse=true)
|
default(show=false, reuse=true)
|
||||||
is_ci() = get(ENV, "CI", "false") == "true"
|
is_ci() = get(ENV, "CI", "false") == "true"
|
||||||
img_tol = is_ci() ? 10e-2 : 10e-2
|
img_tol = is_ci() ? 1e-2 : 1e-3
|
||||||
|
|
||||||
|
## Uncomment the following lines to update reference images for different backends
|
||||||
|
|
||||||
|
#=
|
||||||
|
@testset "GR" begin
|
||||||
|
image_comparison_facts(:gr, tol=img_tol, skip = Plots._backend_skips[:gr])
|
||||||
|
end
|
||||||
|
|
||||||
|
plotly()
|
||||||
|
@testset "Plotly" begin
|
||||||
|
image_comparison_facts(:plotly, tol=img_tol, skip = Plots._backend_skips[:plotlyjs])
|
||||||
|
end
|
||||||
|
|
||||||
|
pyplot()
|
||||||
|
@testset "PyPlot" begin
|
||||||
|
image_comparison_facts(:pyplot, tol=img_tol, skip = Plots._backend_skips[:pyplot])
|
||||||
|
end
|
||||||
|
|
||||||
|
pgfplots()
|
||||||
|
@testset "PGFPlots" begin
|
||||||
|
image_comparison_facts(:pgfplots, tol=img_tol, skip = Plots._backend_skips[:pgfplots])
|
||||||
|
end
|
||||||
|
=#
|
||||||
|
##
|
||||||
|
|
||||||
@testset "Backends" begin
|
@testset "Backends" begin
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user