Merge pull request #2252 from BeastyBlacksmith/pgfplotsx
PGFPlotsX Backend
This commit is contained in:
commit
e903514f70
@ -56,6 +56,7 @@ ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
|
||||
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
||||
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
|
||||
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
|
||||
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
|
||||
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
|
||||
@ -64,4 +65,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
|
||||
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
|
||||
|
||||
[targets]
|
||||
test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"]
|
||||
test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "PGFPlotsX", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"]
|
||||
|
||||
@ -37,7 +37,6 @@ macro init_backend(s)
|
||||
_backendType[Symbol($str)] = $T
|
||||
_backendSymbol[$T] = Symbol($str)
|
||||
_backend_packages[Symbol($str)] = Symbol($package_str)
|
||||
# include("backends/" * $str * ".jl")
|
||||
end)
|
||||
end
|
||||
|
||||
@ -252,6 +251,7 @@ end
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend PGFPlots
|
||||
@init_backend PGFPlotsX
|
||||
@init_backend InspectDR
|
||||
@init_backend HDF5
|
||||
|
||||
@ -661,3 +661,57 @@ const _inspectdr_marker = Symbol[
|
||||
]
|
||||
|
||||
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
||||
# ------------------------------------------------------------------------------
|
||||
# pgfplotsx
|
||||
|
||||
const _pgfplotsx_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:layout,
|
||||
:title, :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip,
|
||||
:match_dimensions,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontrotation, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
|
||||
:legendfontrotation, :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,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:aspect_ratio,
|
||||
:normalize, :weights,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pgfplotsx_seriestype =
|
||||
[:path, :scatter, :straightline,
|
||||
:path3d, :scatter3d, :surface, :wireframe,
|
||||
:heatmap, :contour, :contour3d,
|
||||
:shape,
|
||||
:steppre, :stepmid, :steppost, :ysticks, :xsticks]
|
||||
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_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true
|
||||
|
||||
845
src/backends/pgfplotsx.jl
Normal file
845
src/backends/pgfplotsx.jl
Normal file
@ -0,0 +1,845 @@
|
||||
using Contour: Contour
|
||||
|
||||
Base.@kwdef mutable struct PGFPlotsXPlot
|
||||
is_created::Bool = false
|
||||
was_shown::Bool = false
|
||||
the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument()
|
||||
function PGFPlotsXPlot(is_created, was_shown, the_plot)
|
||||
pgfx_plot = new(is_created, was_shown, the_plot)
|
||||
# tikz libraries
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}")
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{backgrounds}")
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot,
|
||||
"""
|
||||
\\pgfkeys{/tikz/.cd,
|
||||
background color/.initial=white,
|
||||
background color/.get=\\backcol,
|
||||
background color/.store in=\\backcol,
|
||||
}
|
||||
\\tikzset{background rectangle/.style={
|
||||
fill=\\backcol,
|
||||
},
|
||||
use background/.style={
|
||||
show background rectangle
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
# pgfplots libraries
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}")
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween}")
|
||||
pgfx_plot
|
||||
end
|
||||
end
|
||||
|
||||
## end user utility functions
|
||||
function pgfx_axes(pgfx_plot::PGFPlotsXPlot)
|
||||
gp = pgfx_plot.the_plot.elements[1].elements[1]
|
||||
return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp
|
||||
end
|
||||
|
||||
function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend})
|
||||
old_flag = pgfx_plot.attr[:tex_output_standalone]
|
||||
pgfx_plot.attr[:tex_output_standalone] = true
|
||||
fulltext = String(repr("application/x-tex", pgfx_plot))
|
||||
preamble = fulltext[1:first(findfirst("\\begin{document}", fulltext)) - 1]
|
||||
pgfx_plot.attr[:tex_output_standalone] = old_flag
|
||||
preamble
|
||||
end
|
||||
##
|
||||
|
||||
function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface})
|
||||
a = Array(s)
|
||||
xn = Vector{eltype(x)}(undef, length(a))
|
||||
yn = Vector{eltype(y)}(undef, length(a))
|
||||
zn = Vector{eltype(s)}(undef, length(a))
|
||||
for (n, (i, j)) in enumerate(Tuple.(CartesianIndices(a)))
|
||||
xn[n] = x[j]
|
||||
yn[n] = y[i]
|
||||
zn[n] = a[i,j]
|
||||
end
|
||||
return xn, yn, zn
|
||||
end
|
||||
|
||||
function Base.push!(pgfx_plot::PGFPlotsXPlot, item)
|
||||
push!(pgfx_plot.the_plot, item)
|
||||
end
|
||||
|
||||
function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
if !pgfx_plot.is_created
|
||||
the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options())
|
||||
rows, cols = size(plt.layout.grid)
|
||||
bgc = plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : plt.attr[:background_color_outside]
|
||||
if bgc isa Colors.Colorant
|
||||
cstr = plot_color(bgc)
|
||||
a = alpha(cstr)
|
||||
push!(the_plot.options,
|
||||
"draw opacity" => a,
|
||||
"background color" => cstr,
|
||||
"use background" => nothing,
|
||||
)
|
||||
end
|
||||
|
||||
# the combination of groupplot and polaraxis is broken in pgfplots
|
||||
if !any( sp -> ispolar(sp), plt.subplots )
|
||||
pl_height, pl_width = plt.attr[:size]
|
||||
push!( the_plot, PGFPlotsX.GroupPlot(
|
||||
PGFPlotsX.Options(
|
||||
"group style" => PGFPlotsX.Options(
|
||||
"group size" => string(cols)*" by "*string(rows),
|
||||
"horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)),
|
||||
"vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)),
|
||||
),
|
||||
"height" => pl_height > 0 ? string(pl_height)*"px" : "{}",
|
||||
"width" => pl_width > 0 ? string(pl_width)*"px" : "{}",
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
for sp in plt.subplots
|
||||
bb = bbox(sp)
|
||||
cstr = plot_color(sp[:background_color_legend])
|
||||
a = alpha(cstr)
|
||||
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
|
||||
title_cstr = plot_color(sp[:titlefontcolor])
|
||||
title_a = alpha(title_cstr)
|
||||
axis_opt = PGFPlotsX.Options(
|
||||
"height" => string(height(bb)),
|
||||
"width" => string(width(bb)),
|
||||
"title" => sp[:title],
|
||||
"title style" => PGFPlotsX.Options(
|
||||
"font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)),
|
||||
"color" => title_cstr,
|
||||
"draw opacity" => title_a,
|
||||
"rotate" => sp[:titlefontrotation]
|
||||
),
|
||||
"legend style" => PGFPlotsX.Options(
|
||||
pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid") => nothing,
|
||||
"fill" => cstr,
|
||||
"fill opacity" => a,
|
||||
"text opacity" => alpha(plot_color(sp[:legendfontcolor])),
|
||||
"font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp))
|
||||
),
|
||||
"axis background/.style" => PGFPlotsX.Options(
|
||||
"fill" => sp[:background_color_inside]
|
||||
)
|
||||
)
|
||||
# legend position
|
||||
if sp[:legend] isa Tuple
|
||||
x, y = sp[:legend]
|
||||
push!(axis_opt["legend style"], "at={($x, $y)}" )
|
||||
else
|
||||
push!(axis_opt, "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"),
|
||||
)
|
||||
end
|
||||
for letter in (:x, :y, :z)
|
||||
if letter != :z || is3d(sp)
|
||||
pgfx_axis!(axis_opt, sp, letter)
|
||||
end
|
||||
end
|
||||
# Search series for any gradient. In case one series uses a gradient set
|
||||
# the colorbar and colomap.
|
||||
# The reasoning behind doing this on the axis level is that pgfplots
|
||||
# colorbar seems to only works on axis level and needs the proper colormap for
|
||||
# correctly displaying it.
|
||||
# It's also possible to assign the colormap to the series itself but
|
||||
# then the colormap needs to be added twice, once for the axis and once for the
|
||||
# series.
|
||||
# As it is likely that all series within the same axis use the same
|
||||
# colormap this should not cause any problem.
|
||||
for series in series_list(sp)
|
||||
for col in (:markercolor, :fillcolor, :linecolor)
|
||||
if typeof(series.plotattributes[col]) == ColorGradient
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{
|
||||
colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))},
|
||||
}""")
|
||||
push!(axis_opt,
|
||||
"colorbar" => nothing,
|
||||
"colormap name" => "plots$(sp.attr[:subplot_index])",
|
||||
"colormap access" => "direct",
|
||||
)
|
||||
# goto is needed to break out of col and series for
|
||||
@goto colorbar_end
|
||||
end
|
||||
end
|
||||
end
|
||||
@label colorbar_end
|
||||
|
||||
push!(axis_opt, "colorbar style" => PGFPlotsX.Options(
|
||||
"title" => sp[:colorbar_title],
|
||||
"point meta max" => get_clims(sp)[2],
|
||||
"point meta min" => get_clims(sp)[1]
|
||||
)
|
||||
)
|
||||
if is3d(sp)
|
||||
azim, elev = sp[:camera]
|
||||
push!( axis_opt, "view" => (azim, elev) )
|
||||
end
|
||||
axisf = if sp[:projection] == :polar
|
||||
# push!(axis_opt, "xmin" => 90)
|
||||
# push!(axis_opt, "xmax" => 450)
|
||||
PGFPlotsX.PolarAxis
|
||||
else
|
||||
PGFPlotsX.Axis
|
||||
end
|
||||
axis = axisf(
|
||||
axis_opt
|
||||
)
|
||||
for (series_index, series) in enumerate(series_list(sp))
|
||||
opt = series.plotattributes
|
||||
st = series[:seriestype]
|
||||
series_opt = PGFPlotsX.Options(
|
||||
"color" => single_color(opt[:linecolor]),
|
||||
)
|
||||
if is3d(series) || st == :heatmap
|
||||
series_func = PGFPlotsX.Plot3
|
||||
else
|
||||
series_func = PGFPlotsX.Plot
|
||||
end
|
||||
if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
|
||||
push!(series_opt, "area legend" => nothing)
|
||||
end
|
||||
if st == :heatmap
|
||||
push!(axis.options,
|
||||
"view" => "{0}{90}",
|
||||
"shader" => "flat corner",
|
||||
)
|
||||
end
|
||||
# treat segments
|
||||
segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d)
|
||||
iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...)
|
||||
else
|
||||
iter_segments(series)
|
||||
end
|
||||
for (i, rng) in enumerate(segments)
|
||||
segment_opt = PGFPlotsX.Options()
|
||||
segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) )
|
||||
if opt[:markershape] != :none
|
||||
marker = opt[:markershape]
|
||||
if marker isa Shape
|
||||
x = marker.x
|
||||
y = marker.y
|
||||
scale_factor = 0.025
|
||||
mark_size = opt[:markersize] * scale_factor
|
||||
path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ")
|
||||
c = get_markercolor(series, i)
|
||||
a = get_markeralpha(series, i)
|
||||
PGFPlotsX.push_preamble!(pgfx_plot.the_plot,
|
||||
"""
|
||||
\\pgfdeclareplotmark{PlotsShape$(series_index)}{
|
||||
\\filldraw
|
||||
$path;
|
||||
}
|
||||
"""
|
||||
)
|
||||
end
|
||||
segment_opt = merge( segment_opt, pgfx_marker(opt, i) )
|
||||
end
|
||||
if st == :shape ||
|
||||
isfilledcontour(series) ||
|
||||
series[:ribbon] !== nothing
|
||||
segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) )
|
||||
end
|
||||
# add fillrange
|
||||
if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
|
||||
pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng)
|
||||
# add to legend?
|
||||
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
|
||||
io = IOBuffer()
|
||||
PGFPlotsX.print_tex(io, pgfx_fillstyle(opt, i))
|
||||
style = strip(String(take!(io)),['[',']', ' '])
|
||||
push!( segment_opt, "legend image code/.code" => """{
|
||||
\\draw[##1,/tikz/.cd, $style] (0cm,-0.1cm) rectangle (0.6cm,0.1cm);
|
||||
}""" )
|
||||
end
|
||||
end
|
||||
# series
|
||||
coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng )
|
||||
segment_plot = series_func(
|
||||
merge(series_opt, segment_opt),
|
||||
coordinates,
|
||||
)
|
||||
push!(axis, segment_plot)
|
||||
# add ribbons?
|
||||
ribbon = series[:ribbon]
|
||||
if ribbon !== nothing
|
||||
pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index )
|
||||
end
|
||||
# add to legend?
|
||||
if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series)
|
||||
legend = PGFPlotsX.LegendEntry(PGFPlotsX.Options(), opt[:label], true)
|
||||
push!( axis, legend )
|
||||
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
|
||||
end
|
||||
# add subplot annotations
|
||||
anns = sp.attr[:annotations]
|
||||
for (xi,yi,txt) in anns
|
||||
pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp))
|
||||
end
|
||||
end
|
||||
if ispolar(sp)
|
||||
axes = the_plot
|
||||
else
|
||||
axes = the_plot.elements[1]
|
||||
end
|
||||
push!( axes, axis )
|
||||
if length(plt.o.the_plot.elements) > 0
|
||||
plt.o.the_plot.elements[1] = the_plot
|
||||
else
|
||||
push!(plt.o, the_plot)
|
||||
end
|
||||
end
|
||||
pgfx_plot.is_created = true
|
||||
end
|
||||
return pgfx_plot
|
||||
end
|
||||
## seriestype specifics
|
||||
@inline function pgfx_series_coordinates!(sp, series, segment_opt, opt, rng)
|
||||
st = series[:seriestype]
|
||||
# function args
|
||||
args = if st in (:contour, :contour3d)
|
||||
opt[:x], opt[:y], Array(opt[:z])'
|
||||
elseif st in (:heatmap, :surface, :wireframe)
|
||||
surface_to_vecs(opt[:x], opt[:y], opt[:z])
|
||||
elseif is3d(st)
|
||||
opt[:x], opt[:y], opt[:z]
|
||||
elseif st == :straightline
|
||||
straightline_data(series)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
elseif ispolar(sp)
|
||||
theta, r = opt[:x], opt[:y]
|
||||
rad2deg.(theta), r
|
||||
else
|
||||
opt[:x], opt[:y]
|
||||
end
|
||||
seg_args = if st in (:contour, :contour3d)
|
||||
args
|
||||
else
|
||||
(arg[rng] for arg in args)
|
||||
end
|
||||
if opt[:quiver] !== nothing
|
||||
push!(segment_opt, "quiver" => PGFPlotsX.Options(
|
||||
"u" => "\\thisrow{u}",
|
||||
"v" => "\\thisrow{v}",
|
||||
pgfx_arrow(opt[:arrow]) => nothing
|
||||
),
|
||||
)
|
||||
x, y = collect(seg_args)
|
||||
return PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]])
|
||||
else
|
||||
if isfilledcontour(series)
|
||||
st = :filledcontour
|
||||
end
|
||||
pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args)
|
||||
end
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}, Val{:straightline}}, segment_opt, opt, args)
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Union{Val{:scatter}, Val{:scatter3d}}, segment_opt, opt, args)
|
||||
push!( segment_opt, "only marks" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args)
|
||||
push!(segment_opt,
|
||||
"surf" => nothing,
|
||||
"mesh/rows" => length(opt[:x]),
|
||||
"mesh/cols" => length(opt[:y]),
|
||||
)
|
||||
return PGFPlotsX.Table(args...)
|
||||
end
|
||||
|
||||
function pgfx_series_coordinates!(st_val::Val{:steppre}, segment_opt, opt, args)
|
||||
push!( segment_opt, "const plot mark right" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:stepmid}, segment_opt, opt, args)
|
||||
push!( segment_opt, "const plot mark mid" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:steppost}, segment_opt, opt, args)
|
||||
push!( segment_opt, "const plot" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Union{Val{:ysticks},Val{:sticks}}, segment_opt, opt, args)
|
||||
push!( segment_opt, "ycomb" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args)
|
||||
push!( segment_opt, "xcomb" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args)
|
||||
push!( segment_opt, "surf" => nothing,
|
||||
"mesh/rows" => length(opt[:x]),
|
||||
"mesh/cols" => length(opt[:y]),
|
||||
)
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args)
|
||||
push!( segment_opt, "patch" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, args)
|
||||
push!( segment_opt, "mesh" => nothing,
|
||||
"mesh/rows" => length(opt[:x])
|
||||
)
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args)
|
||||
push!( segment_opt, "area legend" => nothing )
|
||||
return PGFPlotsX.Coordinates(args...)
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args)
|
||||
push!(segment_opt,
|
||||
"contour prepared" => PGFPlotsX.Options(
|
||||
"labels" => opt[:contour_labels],
|
||||
),
|
||||
)
|
||||
return PGFPlotsX.Table(Contour.contours(args..., opt[:levels]))
|
||||
end
|
||||
function pgfx_series_coordinates!(st_val::Val{:filledcontour}, segment_opt, opt, args)
|
||||
xs, ys, zs = collect(args)
|
||||
push!(segment_opt,
|
||||
"contour filled" => PGFPlotsX.Options(
|
||||
"labels" => opt[:contour_labels],
|
||||
),
|
||||
"point meta" => "explicit",
|
||||
"shader" => "flat"
|
||||
)
|
||||
if opt[:levels] isa Number
|
||||
push!(segment_opt["contour filled"],
|
||||
"number" => opt[:levels],
|
||||
)
|
||||
elseif opt[:levels] isa AVec
|
||||
push!(segment_opt["contour filled"],
|
||||
"levels" => opt[:levels],
|
||||
)
|
||||
end
|
||||
|
||||
cs = join([
|
||||
join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (i, y) in enumerate(ys)], "\n\n"
|
||||
)
|
||||
"""
|
||||
coordinates {
|
||||
$cs
|
||||
};
|
||||
"""
|
||||
end
|
||||
##
|
||||
const _pgfplotsx_linestyles = KW(
|
||||
:solid => "solid",
|
||||
:dash => "dashed",
|
||||
:dot => "dotted",
|
||||
:dashdot => "dashdotted",
|
||||
:dashdotdot => "dashdotdotted",
|
||||
)
|
||||
|
||||
const _pgfplotsx_markers = KW(
|
||||
:none => "none",
|
||||
:cross => "+",
|
||||
:xcross => "x",
|
||||
:+ => "+",
|
||||
:x => "x",
|
||||
:utriangle => "triangle*",
|
||||
:dtriangle => "triangle*",
|
||||
:rtriangle => "triangle*",
|
||||
:ltriangle => "triangle*",
|
||||
:circle => "*",
|
||||
:rect => "square*",
|
||||
:star5 => "star",
|
||||
:star6 => "asterisk",
|
||||
:diamond => "diamond*",
|
||||
:pentagon => "pentagon*",
|
||||
:hline => "-",
|
||||
:vline => "|"
|
||||
)
|
||||
|
||||
const _pgfplotsx_legend_pos = KW(
|
||||
:bottomleft => "south west",
|
||||
:bottomright => "south east",
|
||||
:topright => "north east",
|
||||
:topleft => "north west",
|
||||
:outertopright => "outer north east",
|
||||
)
|
||||
|
||||
const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
|
||||
const _pgfx_framestyle_defaults = Dict(:semi => :box)
|
||||
|
||||
# we use the anchors to define orientations for example to align left
|
||||
# one needs to use the right edge as anchor
|
||||
const _pgfx_annotation_halign = KW(
|
||||
:center => "",
|
||||
:left => "right",
|
||||
:right => "left"
|
||||
)
|
||||
## --------------------------------------------------------------------------------------
|
||||
# Generates a colormap for pgfplots based on a ColorGradient
|
||||
pgfx_arrow(::Nothing) = "every arrow/.append style={-}"
|
||||
function pgfx_arrow( arr::Arrow )
|
||||
components = String[]
|
||||
head = String[]
|
||||
push!(head, "{stealth[length = $(arr.headlength)pt, width = $(arr.headwidth)pt")
|
||||
if arr.style == :open
|
||||
push!(head, ", open")
|
||||
end
|
||||
push!(head, "]}")
|
||||
head = join(head, "")
|
||||
if arr.side == :both || arr.side == :tail
|
||||
push!( components, head )
|
||||
end
|
||||
push!(components, "-")
|
||||
if arr.side == :both || arr.side == :head
|
||||
push!( components, head )
|
||||
end
|
||||
components = join( components, "" )
|
||||
return "every arrow/.append style={$(components)}"
|
||||
end
|
||||
|
||||
function pgfx_colormap(grad::ColorGradient)
|
||||
join(map(grad.colors) do c
|
||||
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c))
|
||||
end,"\n")
|
||||
end
|
||||
function pgfx_colormap(grad::Vector{<:Colorant})
|
||||
join(map(grad) do c
|
||||
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c))
|
||||
end,"\n")
|
||||
end
|
||||
|
||||
function pgfx_framestyle(style::Symbol)
|
||||
if style in _pgfx_framestyles
|
||||
return style
|
||||
else
|
||||
default_style = get(_pgfx_framestyle_defaults, style, :axes)
|
||||
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
|
||||
default_style
|
||||
end
|
||||
end
|
||||
|
||||
pgfx_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
|
||||
pgfx_thickness_scaling(sp::Subplot) = pgfx_thickness_scaling(sp.plt)
|
||||
pgfx_thickness_scaling(series) = pgfx_thickness_scaling(series[:subplot])
|
||||
|
||||
function pgfx_fillstyle(plotattributes, i = 1)
|
||||
cstr = get_fillcolor(plotattributes, i)
|
||||
a = get_fillalpha(plotattributes, i)
|
||||
if a === nothing
|
||||
a = alpha(single_color(cstr))
|
||||
end
|
||||
PGFPlotsX.Options("fill" => cstr, "fill opacity" => a)
|
||||
end
|
||||
|
||||
function pgfx_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
|
||||
cstr = plot_color(color, α)
|
||||
a = alpha(cstr)
|
||||
return PGFPlotsX.Options(
|
||||
"color" => cstr,
|
||||
"draw opacity" => a,
|
||||
"line width" => linewidth,
|
||||
get(_pgfplotsx_linestyles, linestyle, "solid") => nothing
|
||||
)
|
||||
end
|
||||
|
||||
function pgfx_linestyle(plotattributes, i = 1)
|
||||
lw = pgfx_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i)
|
||||
lc = single_color(get_linecolor(plotattributes, i))
|
||||
la = get_linealpha(plotattributes, i)
|
||||
ls = get_linestyle(plotattributes, i)
|
||||
return pgfx_linestyle(lw, lc, la, ls)
|
||||
end
|
||||
|
||||
function pgfx_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
|
||||
fs = fontsize * thickness_scaling
|
||||
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
|
||||
end
|
||||
|
||||
function pgfx_marker(plotattributes, i = 1)
|
||||
shape = _cycle(plotattributes[:markershape], i)
|
||||
cstr = plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i))
|
||||
a = alpha(cstr)
|
||||
cstr_stroke = plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i))
|
||||
a_stroke = alpha(cstr_stroke)
|
||||
mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)
|
||||
return PGFPlotsX.Options(
|
||||
"mark" => shape isa Shape ? "PlotsShape$i" : get(_pgfplotsx_markers, shape, "*"),
|
||||
"mark size" => "$mark_size pt",
|
||||
"mark options" => PGFPlotsX.Options(
|
||||
"color" => cstr_stroke,
|
||||
"draw opacity" => a_stroke,
|
||||
"fill" => cstr,
|
||||
"fill opacity" => a,
|
||||
"line width" => pgfx_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i),
|
||||
"rotate" => if shape == :dtriangle
|
||||
180
|
||||
elseif shape == :rtriangle
|
||||
270
|
||||
elseif shape == :ltriangle
|
||||
90
|
||||
else
|
||||
0
|
||||
end,
|
||||
get(_pgfplotsx_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid") => nothing
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1)
|
||||
# Construct the style string.
|
||||
cstr = val.font.color
|
||||
a = alpha(cstr)
|
||||
push!(o, ["\\node",
|
||||
PGFPlotsX.Options(
|
||||
get(_pgfx_annotation_halign, val.font.halign, "") => nothing,
|
||||
"color" => cstr,
|
||||
"draw opacity" => convert(Float16, a),
|
||||
"rotate" => val.font.rotation,
|
||||
"font" => pgfx_font(val.font.pointsize, thickness_scaling)
|
||||
),
|
||||
" at (axis cs:$x, $y) {$(val.str)};"
|
||||
])
|
||||
end
|
||||
|
||||
function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index )
|
||||
ribbon_y = series[:ribbon]
|
||||
opt = series.plotattributes
|
||||
if ribbon_y isa AVec
|
||||
ribbon_n = length(opt[:y]) ÷ length(ribbon)
|
||||
ribbon_y = repeat(ribbon, outer = ribbon_n)
|
||||
end
|
||||
# upper ribbon
|
||||
ribbon_name_plus = "plots_rib_p$series_index"
|
||||
ribbon_opt_plus = merge(segment_plot.options, PGFPlotsX.Options(
|
||||
"name path" => ribbon_name_plus,
|
||||
"color" => opt[:fillcolor],
|
||||
"draw opacity" => opt[:fillalpha]
|
||||
))
|
||||
coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .+ ribbon_y)
|
||||
ribbon_plot_plus = series_func(
|
||||
ribbon_opt_plus,
|
||||
coordinates_plus
|
||||
)
|
||||
push!(axis, ribbon_plot_plus)
|
||||
# lower ribbon
|
||||
ribbon_name_minus = "plots_rib_m$series_index"
|
||||
ribbon_opt_minus = merge(segment_plot.options, PGFPlotsX.Options(
|
||||
"name path" => ribbon_name_minus,
|
||||
"color" => opt[:fillcolor],
|
||||
"draw opacity" => opt[:fillalpha]
|
||||
))
|
||||
coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .- ribbon_y)
|
||||
ribbon_plot_plus = series_func(
|
||||
ribbon_opt_minus,
|
||||
coordinates_plus
|
||||
)
|
||||
push!(axis, ribbon_plot_plus)
|
||||
# fill
|
||||
push!(axis, series_func(
|
||||
pgfx_fillstyle(opt, series_index),
|
||||
"fill between [of=$(ribbon_name_plus) and $(ribbon_name_minus)]"
|
||||
))
|
||||
return axis
|
||||
end
|
||||
|
||||
function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng)
|
||||
fillrange_opt = PGFPlotsX.Options(
|
||||
"line width" => "0",
|
||||
"draw opacity" => "0",
|
||||
)
|
||||
fillrange_opt = merge( fillrange_opt, pgfx_fillstyle(series, i) )
|
||||
fillrange_opt = merge( fillrange_opt, pgfx_marker(series, i) )
|
||||
push!( fillrange_opt, "forget plot" => nothing )
|
||||
opt = series.plotattributes
|
||||
args = is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) : (opt[:x][rng], opt[:y][rng])
|
||||
push!(axis, PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...)))
|
||||
return axis
|
||||
end
|
||||
|
||||
function pgfx_fillrange_args(fillrange, x, y)
|
||||
n = length(x)
|
||||
x_fill = [x; x[n:-1:1]; x[1]]
|
||||
y_fill = [y; _cycle(fillrange, n:-1:1); y[1]]
|
||||
return PGFPlotsX.Coordinates(x_fill, y_fill)
|
||||
end
|
||||
|
||||
function pgfx_fillrange_args(fillrange, x, y, z)
|
||||
n = length(x)
|
||||
x_fill = [x; x[n:-1:1]; x[1]]
|
||||
y_fill = [y; y[n:-1:1]; x[1]]
|
||||
z_fill = [z; _cycle(fillrange, n:-1:1); z[1]]
|
||||
return PGFPlotsX.Coordiantes(x_fill, y_fill, z_fill)
|
||||
end
|
||||
# --------------------------------------------------------------------------------------
|
||||
function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
axis = sp[Symbol(letter,:axis)]
|
||||
|
||||
# turn off scaled ticks
|
||||
push!(opt, "scaled $(letter) ticks" => "false",
|
||||
string(letter,:label) => axis[:guide],
|
||||
)
|
||||
|
||||
# set to supported framestyle
|
||||
framestyle = pgfx_framestyle(sp[:framestyle] == false ? :none : sp[:framestyle])
|
||||
|
||||
# axis label position
|
||||
labelpos = ""
|
||||
if letter == :x && axis[:guide_position] == :top
|
||||
labelpos = "at={(0.5,1)},above,"
|
||||
elseif letter == :y && axis[:guide_position] == :right
|
||||
labelpos = "at={(1,0.5)},below,"
|
||||
end
|
||||
|
||||
# Add label font
|
||||
cstr = plot_color(axis[:guidefontcolor])
|
||||
α = alpha(cstr)
|
||||
push!(opt, string(letter, "label style") => PGFPlotsX.Options(
|
||||
labelpos => nothing,
|
||||
"font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)),
|
||||
"color" => cstr,
|
||||
"draw opacity" => α,
|
||||
"rotate" => axis[:guidefontrotation],
|
||||
)
|
||||
)
|
||||
|
||||
# flip/reverse?
|
||||
axis[:flip] && push!(opt, "$letter dir" => "reverse")
|
||||
|
||||
# scale
|
||||
scale = axis[:scale]
|
||||
if scale in (:log2, :ln, :log10)
|
||||
push!(opt, string(letter,:mode) => "log")
|
||||
scale == :ln || push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)")
|
||||
end
|
||||
|
||||
# ticks on or off
|
||||
if axis[:ticks] in (nothing, false, :none) || framestyle == :none
|
||||
push!(opt, "$(letter)majorticks" => "false")
|
||||
end
|
||||
|
||||
# grid on or off
|
||||
if axis[:grid] && framestyle != :none
|
||||
push!(opt, "$(letter)majorgrids" => "true")
|
||||
else
|
||||
push!(opt, "$(letter)majorgrids" => "false")
|
||||
end
|
||||
|
||||
# limits
|
||||
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter)
|
||||
push!( opt,
|
||||
string(letter,:min) => lims[1],
|
||||
string(letter,:max) => lims[2]
|
||||
)
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||
ticks = get_ticks(sp, axis)
|
||||
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
|
||||
push!(opt, string(letter, "tick") => string("{", join(tick_values,","), "}"))
|
||||
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
|
||||
# wrap the power part of label with }
|
||||
tick_labels = Vector{String}(undef, length(ticks[2]))
|
||||
for (i, label) in enumerate(ticks[2])
|
||||
base, power = split(label, "^")
|
||||
power = string("{", power, "}")
|
||||
tick_labels[i] = string(base, "^", power)
|
||||
end
|
||||
push!(opt, string(letter, "ticklabels") => string("{\$", join(tick_labels,"\$,\$"), "\$}"))
|
||||
elseif axis[:showaxis]
|
||||
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
|
||||
if axis[:formatter] in (:scientific, :auto)
|
||||
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
|
||||
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
|
||||
end
|
||||
push!(opt, string(letter, "ticklabels") => string("{", join(tick_labels,","), "}"))
|
||||
else
|
||||
push!(opt, string(letter, "ticklabels") => "{}")
|
||||
end
|
||||
push!(opt, string(letter, "tick align") => (axis[:tick_direction] == :out ? "outside" : "inside"))
|
||||
cstr = plot_color(axis[:tickfontcolor])
|
||||
α = alpha(cstr)
|
||||
push!(opt, string(letter, "ticklabel style") => PGFPlotsX.Options(
|
||||
"font" => pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)),
|
||||
"color" => cstr,
|
||||
"draw opacity" => α,
|
||||
"rotate" => axis[:tickfontrotation]
|
||||
)
|
||||
)
|
||||
push!(opt, string(letter, " grid style") => pgfx_linestyle(pgfx_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle])
|
||||
)
|
||||
end
|
||||
|
||||
# framestyle
|
||||
if framestyle in (:axes, :origin)
|
||||
axispos = framestyle == :axes ? "left" : "middle"
|
||||
if axis[:draw_arrow]
|
||||
push!(opt, string("axis ", letter, " line") => axispos)
|
||||
else
|
||||
# the * after line disables the arrow at the axis
|
||||
push!(opt, string("axis ", letter, " line*") => axispos)
|
||||
end
|
||||
end
|
||||
|
||||
if framestyle == :zerolines
|
||||
push!(opt, string("extra ", letter, " ticks") => "0")
|
||||
push!(opt, string("extra ", letter, " tick labels") => "")
|
||||
push!(opt, string("extra ", letter, " tick style") => PGFPlotsX.Options(
|
||||
"grid" => "major",
|
||||
"major grid style" => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
if !axis[:showaxis]
|
||||
push!(opt, "separate axis lines")
|
||||
end
|
||||
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
|
||||
push!(opt, string(letter, " axis line style") => "{draw opacity = 0}")
|
||||
else
|
||||
push!(opt, string(letter, " axis line style") => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0)
|
||||
)
|
||||
end
|
||||
end
|
||||
# --------------------------------------------------------------------------------------
|
||||
# display calls this and then _display, its called 3 times for plot(1:5)
|
||||
# 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
|
||||
# order: right, top, left, bottom
|
||||
sp.minpad = (22mm + sp[:right_margin],
|
||||
12mm + sp[:top_margin],
|
||||
2mm + sp[:left_margin],
|
||||
10mm + sp[:bottom_margin])
|
||||
end
|
||||
|
||||
function _create_backend_figure(plt::Plot{PGFPlotsXBackend})
|
||||
plt.o = PGFPlotsXPlot()
|
||||
end
|
||||
|
||||
function _series_added(plt::Plot{PGFPlotsXBackend}, series::Series)
|
||||
plt.o.is_created = false
|
||||
end
|
||||
|
||||
function _update_plot_object(plt::Plot{PGFPlotsXBackend})
|
||||
plt.o(plt)
|
||||
end
|
||||
|
||||
for mime in ("application/pdf", "image/png", "image/svg+xml")
|
||||
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{PGFPlotsXBackend})
|
||||
show(io, mime, plt.o.the_plot)
|
||||
end
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlotsXBackend})
|
||||
PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone])
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PGFPlotsXBackend})
|
||||
display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot)
|
||||
end
|
||||
@ -46,6 +46,12 @@ function __init__()
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
|
||||
end
|
||||
|
||||
@require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin
|
||||
fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl")
|
||||
include(fn)
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
|
||||
end
|
||||
|
||||
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin
|
||||
fn = joinpath(@__DIR__, "backends", "plotlyjs.jl")
|
||||
include(fn)
|
||||
|
||||
@ -8,6 +8,8 @@ using Gtk
|
||||
using LibGit2
|
||||
using GeometryTypes
|
||||
|
||||
include("test_pgfplotsx.jl")
|
||||
|
||||
reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
|
||||
|
||||
function reference_file(backend, i, version)
|
||||
|
||||
136
test/test_pgfplotsx.jl
Normal file
136
test/test_pgfplotsx.jl
Normal file
@ -0,0 +1,136 @@
|
||||
using Plots, Test
|
||||
pgfplotsx()
|
||||
|
||||
function create_plot( args...; kwargs... )
|
||||
pgfx_plot = plot(args...; kwargs...)
|
||||
return pgfx_plot, repr("application/x-tex", pgfx_plot)
|
||||
end
|
||||
|
||||
function create_plot!( args...; kwargs... )
|
||||
pgfx_plot = plot!(args...; kwargs...)
|
||||
return pgfx_plot, repr("application/x-tex", pgfx_plot)
|
||||
end
|
||||
|
||||
@testset "PGFPlotsX" begin
|
||||
pgfx_plot = plot(1:5)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
@test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument
|
||||
@test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing
|
||||
|
||||
@testset "3D docs example" begin
|
||||
n = 100
|
||||
ts = range(0, stop=8π, length=n)
|
||||
x = ts .* map(cos, ts)
|
||||
y = (0.1ts) .* map(sin, ts)
|
||||
z = 1:n
|
||||
pl = plot(x, y, z, zcolor=reverse(z), m=(10, 0.8, :blues, Plots.stroke(0)), leg=false, cbar=true, w=5)
|
||||
pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w=10)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true)
|
||||
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
|
||||
end
|
||||
end # testset
|
||||
@testset "Color docs example" begin
|
||||
y = rand(100)
|
||||
plot(0:10:100, rand(11, 4), lab="lines", w=3, palette=:grays, fill=0, α=0.6)
|
||||
pl = scatter!(y, zcolor=abs.(y .- 0.5), m=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad")
|
||||
Plots._update_plot_object(pl)
|
||||
axis = Plots.pgfx_axes(pl.o)[1]
|
||||
@test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5
|
||||
@test count( x->x isa PGFPlotsX.Plot, axis.contents ) == 108 # each marker is its own plot, fillranges create 2 plot-objects
|
||||
marker = axis.contents[15]
|
||||
@test marker isa PGFPlotsX.Plot
|
||||
@test marker.options["mark"] == "*"
|
||||
@test marker.options["mark options"]["color"] == RGBA{Float64}( colorant"green", 0.8)
|
||||
@test marker.options["mark options"]["line width"] == 1
|
||||
end # testset
|
||||
@testset "Plot in pieces" begin
|
||||
plot(rand(100) / 3, reg=true, fill=(0, :green))
|
||||
scatter!(rand(100), markersize=6, c=:orange)
|
||||
end # testset
|
||||
@testset "Marker types" begin
|
||||
markers = filter((m->begin
|
||||
m in Plots.supported_markers()
|
||||
end), Plots._shape_keys)
|
||||
markers = reshape(markers, 1, length(markers))
|
||||
n = length(markers)
|
||||
x = (range(0, stop=10, length=n + 2))[2:end - 1]
|
||||
y = repeat(reshape(reverse(x), 1, :), n, 1)
|
||||
scatter(x, y, m=(8, :auto), lab=map(string, markers), bg=:linen, xlim=(0, 10), ylim=(0, 10))
|
||||
end # testset
|
||||
@testset "Layout" begin
|
||||
plot(Plots.fakedata(100, 10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black])
|
||||
end # testset
|
||||
@testset "Polar plots" begin
|
||||
Θ = range(0, stop=1.5π, length=100)
|
||||
r = abs.(0.1 * randn(100) + sin.(3Θ))
|
||||
plot(Θ, r, proj=:polar, m=2)
|
||||
end # testset
|
||||
@testset "Drawing shapes" begin
|
||||
verts = [(-1.0, 1.0), (-1.28, 0.6), (-0.2, -1.4), (0.2, -1.4), (1.28, 0.6), (1.0, 1.0), (-1.0, 1.0), (-0.2, -0.6), (0.0, -0.2), (-0.4, 0.6), (1.28, 0.6), (0.2, -1.4), (-0.2, -1.4), (0.6, 0.2), (-0.2, 0.2), (0.0, -0.2), (0.2, 0.2), (-0.2, -0.6)]
|
||||
x = 0.1:0.2:0.9
|
||||
y = 0.7 * rand(5) .+ 0.15
|
||||
plot(x, y, line=(3, :dash, :lightblue), marker=(Shape(verts), 30, RGBA(0, 0, 0, 0.2)), bg=:pink, fg=:darkblue, xlim=(0, 1), ylim=(0, 1), leg=false)
|
||||
end # testset
|
||||
@testset "Histogram 2D" begin
|
||||
histogram2d(randn(10000), randn(10000), nbins=20)
|
||||
end # testset
|
||||
@testset "Heatmap-like" begin
|
||||
xs = [string("x", i) for i = 1:10]
|
||||
ys = [string("y", i) for i = 1:4]
|
||||
z = float((1:4) * reshape(1:10, 1, :))
|
||||
pgfx_plot = heatmap(xs, ys, z, aspect_ratio=1)
|
||||
Plots._update_plot_object(pgfx_plot)
|
||||
if @test_nowarn(haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true)
|
||||
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
|
||||
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1"
|
||||
end
|
||||
|
||||
pgfx_plot = wireframe(xs, ys, z, aspect_ratio=1)
|
||||
# TODO: clims are wrong
|
||||
end # testset
|
||||
@testset "Contours" begin
|
||||
x = 1:0.5:20
|
||||
y = 1:0.5:10
|
||||
f(x, y) = begin
|
||||
(3x + y ^ 2) * abs(sin(x) + cos(y))
|
||||
end
|
||||
X = repeat(reshape(x, 1, :), length(y), 1)
|
||||
Y = repeat(y, 1, length(x))
|
||||
Z = map(f, X, Y)
|
||||
p2 = contour(x, y, Z)
|
||||
p1 = contour(x, y, f, fill=true)
|
||||
plot(p1, p2)
|
||||
# TODO: colorbar for filled contours
|
||||
end # testset
|
||||
@testset "Varying colors" begin
|
||||
t = range(0, stop=1, length=100)
|
||||
θ = (6π) .* t
|
||||
x = t .* cos.(θ)
|
||||
y = t .* sin.(θ)
|
||||
p1 = plot(x, y, line_z=t, linewidth=3, legend=false)
|
||||
p2 = scatter(x, y, marker_z=((x, y)->begin
|
||||
x + y
|
||||
end), color=:bluesreds, legend=false)
|
||||
plot(p1, p2)
|
||||
end # testset
|
||||
@testset "Framestyles" begin
|
||||
scatter(fill(randn(10), 6), fill(randn(10), 6), framestyle=[:box :semi :origin :zerolines :grid :none], title=[":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], color=permutedims(1:6), layout=6, label="", markerstrokewidth=0, ticks=-2:2)
|
||||
# TODO: support :semi
|
||||
end # testset
|
||||
@testset "Quiver" begin
|
||||
x = -2pi:0.2:2*pi
|
||||
y = sin.(x)
|
||||
|
||||
u = ones(length(x))
|
||||
v = cos.(x)
|
||||
plot( x, y, quiver = (u, v), arrow = true )
|
||||
# TODO: could adjust limits to fit arrows if too long, but how?
|
||||
end # testset
|
||||
@testset "Annotations" begin
|
||||
y = rand(10)
|
||||
plot(y, annotations=(3, y[3], Plots.text("this is \\#3", :left)), leg=false)
|
||||
annotate!([(5, y[5], Plots.text("this is \\#5", 16, :red, :center)), (10, y[10], Plots.text("this is \\#10", :right, 20, "courier"))])
|
||||
scatter!(range(2, stop=8, length=6), rand(6), marker=(50, 0.2, :orange), series_annotations=["series", "annotations", "map", "to", "series", Plots.text("data", :green)])
|
||||
end # testset
|
||||
end # testset
|
||||
Loading…
x
Reference in New Issue
Block a user