merged dev into tb_recipes

This commit is contained in:
Thomas Breloff 2016-05-19 13:03:01 -04:00
commit 1cf514d1e6
3 changed files with 223 additions and 78 deletions

124
NEWS.md Normal file
View File

@ -0,0 +1,124 @@
# Plots.jl NEWS
#### notes on release changes, ongoing development, and future planned work
- I (@tbreloff) am in development of totally revamped internals, in which much of the logic in building series is changed to recursively stacking recipes in a modular fashion. I'll write a blog post sometime soon detailing why this is amazing, but for now you can get a taste of it by looking at the [RecipesBase readme](https://github.com/JuliaPlots/RecipesBase.jl)
- Version 0.6.2 will be the last full release of the "Old Plots", and the 0.6 minor will be only small bug fixes.
- All new development should target 0.7 (recipes and subplots)!
## 0.7 (WIP on tb_recipes/dev and master)
- Revamped and simplified internals
- [Recipes, recipes, recipes](https://github.com/JuliaPlots/RecipesBase.jl/issues/6)
- [Layouts and Subplots](https://github.com/tbreloff/Plots.jl/issues/60)
## Version 0.6
#### 0.6.2
- `linewidth` fixes
- `markershape` fix
- converted center calc to centroid for shapes
- new dependency on [RecipesBase](https://github.com/JuliaPlots/RecipesBase.jl)
- REQUIRE upper limit for RecipesBase: 0.0.1
- GR fixes/improvements (@jheinen)
- support `zlims`, `bins`
- allow Plots colormaps
- other bug fixes
- native image support
- PGFPlots fixes/improvements (@pkofod)
- DataFrames are handled by recipes
- Plotly: zaxis, tick rotation, 3d axis fix
- Improvements in handling discrete data
- Support for image display
- `arrow` keyword and support for adding arrows to paths
- changed quiver recipe to use arrows
- Bug fixes for boxplots, heatmaps, and more
#### 0.6.1
- `rotation` keyword
- improved supported graphs
- subplot bug fix
#### 0.6.0
- `apply_series_recipe` framework for built-in recipes
- [boxplot/violin recipes](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/boxplot.ipynb)
- [errorbar/ribbon recipes](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/errorbars.ipynb)
- [quiver recipe](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/quiver.ipynb)
- `polar` coordinates
- better support for shapes and custom polygons (see [batman](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/batman.ipynb))
- z-axis keywords
- 3D indexing overhaul: `push!`, `append!` support
- matplotlib colormap constants (`:inferno` is the new default colormap for Plots)
- `typealias KW Dict{Symbol,Any}` used in place of splatting in many places
- png generation for plotly backend using wkhtmltoimage
- `normalize` and `weights` keywords
- background/foreground subcategories for fine-tuning of looks
- `add_theme`/`set_theme` and ggplot2 theme (see [this issue](https://github.com/tbreloff/Plots.jl/issues/201))
- `PLOTS_DEFAULT_BACKEND` environment variable
- `barh` linetype
- support for non-gridded surfaces with pyplot's trisurface
- pyplot surface zcolor
- internal refactor of supported.jl
- `wrap` method to bypass input processing
- `translate`, `scale` and `rotate` methods for coordinates and shapes
- and many more minor fixes and improvements
#### 0.5.4
- old heatmaps have been renamed to hist2d, and true heatmaps implemented (see https://github.com/tbreloff/Plots.jl/issues/147)
- lots of reorganization and redesign of the internals
- lots of renaming to keep to conventions: AbstractPlot, AbstractBackend, etc
- initial redesign of layouts
- integration with Atom PlotPane
- arc diagram and chord diagram (thanks to @diegozea: see https://github.com/tbreloff/Plots.jl/issues/163)
- work on GR, GLVisualize, and PGFPlots backends (thanks @jheinen @dlfivefifty @pkofod)
- improvements to Plotly setup (thanks @spencerlyon2)
- overhaul to series creation logic and groupby mechanic
- replace Dict with `typealias KW Dict{Symbol,Any}` in many places, also replacing keyword arg splatting
- new `shape` linetype for plotting polygons in plot-coordinates (see https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/batman.ipynb)
- many other fixes
#### 0.5.3
- `@gif` macro with `every`/`when` syntax
- bezier curves and other graph drawing helpers
- added FixedSizeArrays dependency with relevant functionality
- merged lots of improvements to GR (thanks @jheinen)
- `overwrite_figure`/`reuse` arg for reusing the same figure window
- deprecated Qwt, Winston, and Bokeh backends
- improved handling of 3D inputs (call `z=rand(10,10); surface(z)` for example)
- fix IJulia display issue
- lots of progress on PlotlyJS backend
- and many other changes and fixes...
#### 0.5.2
- Added [GR.jl](https://github.com/jheinen/GR.jl) as a backend (unfinished but functional) All credit to @jheinen
- Set defaults within backend calls (i.e. `gadfly(legend=false)`)
- `abline!`; also extrema allows plotting functions without giving x (i.e. `plot(cos, 0, 10); plot!(sin)`) @pkofod @joshday
- Integration with [PlotlyJS.jl](https://github.com/spencerlyon2/PlotlyJS.jl) for using Plotly inside a Blink window @spencerlyon2
- The Plotly backend has been split into my built-in version (`plotly()`) and @spencerlyon2's backend (`plotlyjs()`)
- Revamped backend setup code for easily adding new backends
- New docs (WIP) at http://plots.readthedocs.org/
- Overhaul to `:legend` keyword (see https://github.com/tbreloff/Plots.jl/issues/135)
- New dependency on Requires, allows auto-loading of DataFrames support
- Support for plotting lists of Tuples and FixedSizeArrays
- new `@animate` macro for super simple animations (see https://github.com/tbreloff/Plots.jl/issues/111#issuecomment-181515616)
- allow Function for `:fillrange` and `zcolor` arguments (for example: `scatter(sin, 0:10, marker=15, fill=(cos,0.4), zcolor=sin)`)
- allow vectors of PlotText without x/y coords (for example: `scatter(rand(10), m=20, ann=map(text, 1:10))`)
- Lots and lots of fixes
#### 0.5.1
#### 0.5.0
- `with` function for temporary defaults
- contours
- basic 3D plotting
- preliminary support for Bokeh
- `stroke` and `brush` for more fine-tuned control over visuals
- smarter "magic" arguments: `line`, `marker`

View File

@ -36,14 +36,18 @@ supportedArgs(::GRBackend) = [
:aspect_ratio
]
supportedAxes(::GRBackend) = _allAxes
supportedTypes(::GRBackend) = [:none, :line, :path, :steppre, :steppost, :sticks,
:scatter, :hist2d, :hexbin, :hist, :density, :bar,
:hline, :vline, :contour, :heatmap, :path3d, :scatter3d, :surface,
:wireframe, :ohlc, :pie]
supportedTypes(::GRBackend) = [
:none, :line, :path, :steppre, :steppost,
:scatter, :hist2d, :hexbin, :hist, :density,
:bar, :sticks,
:hline, :vline, :heatmap, :pie, :image, :ohlc,
:contour, :path3d, :scatter3d, :surface, :wireframe
]
supportedStyles(::GRBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GRBackend) = vcat(_allMarkers, Shape)
supportedScales(::GRBackend) = [:identity, :log10]
subplotSupported(::GRBackend) = true
nativeImagesSupported(::GRBackend) = true
# --------------------------------------------------------------------------------------
@ -435,9 +439,9 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
GR.setcolormap(1000 + GR.COLORMAP_COOLWARM)
legend = false
legend = falses(length(plt.seriesargs))
for p in plt.seriesargs
for (ind, p) in enumerate(plt.seriesargs)
st = p[:seriestype]
if st in (:hist2d, :hexbin, :contour, :surface, :wireframe, :heatmap)
if isa(p[:fillcolor], ColorGradient)
@ -470,13 +474,13 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
end
GR.polyline(p[:x], p[:y])
end
legend = true
legend[ind] = true
end
if st == :line
if length(p[:x]) > 1
gr_polyline(p[:x], p[:y])
end
legend = true
legend[ind] = true
elseif st in [:steppre, :steppost]
n = length(p[:x])
x = zeros(2*n + 1)
@ -496,13 +500,13 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
if n > 1
GR.polyline(x, y)
end
legend = true
legend[ind] = true
elseif st == :sticks
x, y = p[:x], p[:y]
for i = 1:length(y)
GR.polyline([x[i], x[i]], [ymin, y[i]])
end
legend = true
legend[ind] = true
elseif st == :scatter || (p[:markershape] != :none && axes_2d)
GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
gr_setmarkershape(p)
@ -523,7 +527,7 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
gr_polymarker(p, [p[:x][i]], [p[:y][i]])
end
end
legend = true
legend[ind] = true
elseif st == :bar
y = p[:y]
for i = 1:length(y)
@ -574,6 +578,7 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
charheight = max(0.016 * diag, 0.01)
GR.setcharheight(charheight)
GR.colormap()
GR.setviewport(viewport[1], viewport[2], viewport[3], viewport[4])
elseif st == :contour
x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false)
zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), false)
@ -594,6 +599,7 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
charheight = max(0.016 * diag, 0.01)
GR.setcharheight(charheight)
GR.axes(0, ztick, xmax, zmin, 0, 1, 0.005)
GR.setviewport(viewport[1], viewport[2], viewport[3], viewport[4])
elseif st in [:surface, :wireframe]
x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false)
zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true)
@ -630,11 +636,12 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true)
GR.setspace(zmin, zmax, 0, 90)
z = reshape(z, length(x) * length(y))
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
GR.surface(x, y, z, GR.OPTION_COLORED_MESH)
if cmap
GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
viewport[3], viewport[4])
GR.colormap()
GR.setviewport(viewport[1], viewport[2], viewport[3], viewport[4])
end
elseif st in [:path3d, :scatter3d]
x, y, z = p[:x], p[:y], p[:z]
@ -722,6 +729,19 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
a1 = a2
end
GR.selntran(1)
elseif st == :image
img = p[:z].surf
w, h = size(img)
if eltype(img) <: Colors.AbstractGray
grey = round(UInt8, float(img) * 255)
rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey)
else
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
round(Int, blue(c) * 255) << 16 +
round(Int, green(c) * 255) << 8 +
round(Int, red(c) * 255) ), img)
end
GR.drawimage(xmin, xmax, ymin, ymax, w, h, rgba)
elseif st == :polar
xmin, xmax, ymin, ymax = viewport
ymax -= 0.05 * (xmax - xmin)
@ -746,15 +766,15 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
GR.restorestate()
end
if d[:legend] != :none && legend
if d[:legend] != :none && any(legend) == true
GR.savestate()
GR.selntran(0)
GR.setscale(0)
w = 0
i = 0
n = 0
for p in plt.seriesargs
if p[:label] == ""
for (ind, p) in enumerate(plt.seriesargs)
if !legend[ind] || p[:label] == ""
continue
end
n += 1
@ -777,8 +797,8 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
GR.setlinewidth(1)
GR.drawrect(px - 0.08, px + w + 0.02, py + dy, py - dy * n)
i = 0
for p in plt.seriesargs
if p[:label] == ""
for (ind, p) in enumerate(plt.seriesargs)
if !legend[ind] || p[:label] == ""
continue
end
GR.setlinewidth(p[:linewidth])

View File

@ -24,7 +24,7 @@ supportedArgs(::PGFPlotsBackend) = [
:markercolor,
:markersize,
:markeralpha,
# :markerstrokewidth,
:markerstrokewidth,
:markerstrokecolor,
:markerstrokestyle,
# :n,
@ -34,7 +34,7 @@ supportedArgs(::PGFPlotsBackend) = [
# :pos,
# :smooth,
# :show,
# :size,
:size,
:title,
# :windowtitle,
:x,
@ -87,17 +87,17 @@ const _pgfplots_linestyles = KW(
)
const _pgfplots_markers = KW(
:none => "mark = none,",
:cross => "mark = +,",
:xcross => "mark = x,",
:utriangle => "mark = triangle*,",
:dtriangle => "mark = triangle*,",
:ellipse => "mark = o*,",
:rect => "mark = square*,",
:star5 => "mark = star,",
:star6 => "mark = asterisk,",
:diamond => "mark = diamond*,",
:pentagon => "mark = pentagon*,"
:none => "none",
:cross => "+",
:xcross => "x",
:utriangle => "triangle*",
:dtriangle => "triangle*",
:ellipse => "o*",
:rect => "square*",
:star5 => "star",
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*"
)
const _pgfplots_legend_pos = KW(
@ -120,50 +120,52 @@ end
function _pgfplots_get_linestyle!(kwargs, plt)
ls = plt[:linestyle]
if haskey(_pgfplots_linestyles, ls)
kwargs[:style] *= _pgfplots_linestyles[ls]*","
push!(kwargs[:style], _pgfplots_linestyles[ls])
end
kwargs[:style] *= "line width = $(plt[:linewidth]) pt"*","
push!(kwargs[:style], "line width = $(plt[:linewidth]) pt")
end
function _pgfplots_get_marker!(kwargs, plt)
# Control marker shape
# Control marker shape, size, colors, alphas, and stroke width
mark = plt[:markershape]
kwargs[:style] *= _pgfplots_markers[mark]
# Control marker size
kwargs[:style] *= "mark size = $(plt[:markersize]/2),"
# Control marker colors and alphas
α = plt[:markeralpha] == nothing ? 1.0 : plt[:markeralpha]
kwargs[:style] *= "mark options = {color=$(_pgfplots_get_color(plt, :markerstrokecolor)),"
kwargs[:style] *= mark == :dtriangle ? "rotate=180," : ""
kwargs[:style] *= "fill=$(_pgfplots_get_color(plt, :markercolor)),"
kwargs[:style] *= "fill opacity = $α,"
markstrokestyle = plt[:markerstrokestyle]
if haskey(_pgfplots_linestyles, markstrokestyle)
kwargs[:style] *= _pgfplots_linestyles[markstrokestyle]
push!(kwargs[:style], "mark = " * _pgfplots_markers[mark],
"mark size = $(plt[:markersize]/2)",
"mark options = {color=$(_pgfplots_get_color(plt, :markerstrokecolor))",
"fill=$(_pgfplots_get_color(plt, :markercolor))",
"fill opacity = $α",
"line width=$(plt[:markerstrokewidth])")
# Rotate the marker if :dtriangle was chosen
mark == :dtriangle && push!(kwargs[:style], "rotate=180")
# Apply marker stroke style if it is a valid PGFPlots stroke style
if haskey(_pgfplots_linestyles, plt[:markerstrokestyle])
push!(kwargs[:style], _pgfplots_linestyles[plt[:markerstrokestyle]])
end
kwargs[:style] *= "},"
# End the open mark options bracker
push!(kwargs[:style], "}")
end
function _pgfplots_get_series_color!(kwargs, plt)
α = plt[:seriesalpha] == nothing ? 1.0 : plt[:seriesalpha]
kwargs[:style] *= "color=$(_pgfplots_get_color(plt, :seriescolor)),"
kwargs[:style] *= "draw opacity = $α,"
push!(kwargs[:style], "color=$(_pgfplots_get_color(plt, :seriescolor))",
"draw opacity = $α")
end
function _pgfplots_get_line_color!(kwargs, plt)
α = plt[:linealpha] == nothing ? 1.0 : plt[:linealpha]
kwargs[:style] *= "color=$(_pgfplots_get_color(plt, :linecolor)),"
kwargs[:style] *= "draw opacity = $α,"
kwargs[:style] *= ", color=$(_pgfplots_get_color(plt, :linecolor))" *
", draw opacity = $α"
end
function _pgfplots_get_fill_color!(kwargs, plt)
α = plt[:fillalpha] == nothing ? 1.0 : plt[:fillalpha]
kwargs[:style] *= "fill=$(_pgfplots_get_color(plt, :fillcolor)),"
kwargs[:style] *= "fill opacity = $α,"
kwargs[:style] *= ", fill=$(_pgfplots_get_color(plt, :fillcolor))" *
", fill opacity = $α"
end
function _pgfplots_get_label!(kwargs, plt)
@ -172,55 +174,55 @@ function _pgfplots_get_label!(kwargs, plt)
end
end
function _pgfplots_get_plot_kwargs(plt)
kwargs = KW()
kwargs[:style] = ""
kwargs[:style] = []
_pgfplots_get_linestyle!(kwargs, plt)
_pgfplots_get_marker!(kwargs, plt)
_pgfplots_get_series_color!(kwargs, plt)
_pgfplots_get_label!(kwargs, plt)
kwargs[:style] = join(kwargs[:style], ',')
kwargs
end
function _pgfplots_axis(plt_series)
line_type = plt_series[:seriestype]
plt_kwargs = _pgfplots_get_plot_kwargs(plt_series)
if line_type == :path
if line_type == :path
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :path3d
PGFPlots.Linear3(plt_series[:x], plt_series[:y], plt_series[:z]; plt_kwargs...)
elseif line_type == :scatter
PGFPlots.Scatter(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :steppre
plt_kwargs[:style] *= "const plot mark right,"
plt_kwargs[:style] *= ", const plot mark right"
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :stepmid
plt_kwargs[:style] *= "const plot mark mid,"
plt_kwargs[:style] *= ", const plot mark mid"
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :steppost
plt_kwargs[:style] *= "const plot,"
plt_kwargs[:style] *= ", const plot"
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :hist
#TODO patch this in PGFPlots.jl instead; the problem is that PGFPlots will
# save _all_ data points in the figure which can be quite heavy
plt_hist = hist(plt_series[:y])
plt_kwargs[:style] *= "ybar interval,"
plt_kwargs[:style] *= ", ybar interval"
_pgfplots_get_line_color!(plt_kwargs, plt_series)
_pgfplots_get_fill_color!(plt_kwargs, plt_series)
PGFPlots.Linear(plt_hist[1][1:end-1]+plt_hist[1].step/2, plt_hist[2]; plt_kwargs...)
elseif line_type == :hist2d
PGFPlots.Histogram2(plt_series[:x], plt_series[:y])
elseif line_type == :bar
plt_kwargs[:style] *= "ybar,"
plt_kwargs[:style] *= ", ybar"
_pgfplots_get_line_color!(plt_kwargs, plt_series)
_pgfplots_get_fill_color!(plt_kwargs, plt_series)
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :sticks || line_type == :ysticks
plt_kwargs[:style] *= "ycomb"
plt_kwargs[:style] *= ", ycomb"
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :xsticks
plt_kwargs[:style] *= "xcomb"
plt_kwargs[:style] *= ", xcomb"
PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
elseif line_type == :contour
PGFPlots.Contour(plt_series[:z].surf, plt_series[:x], plt_series[:y])
@ -300,36 +302,36 @@ function _pgfplots_get_axis_kwargs(d)
for arg in (:xguide, :yguide, :zguide, :title)
axisargs[arg] = d[arg]
end
axisargs[:style] = ""
axisargs[:style] *= d[:xflip] == true ? "x dir=reverse," : ""
axisargs[:style] *= d[:yflip] == true ? "y dir=reverse," : ""
axisargs[:style] = []
d[:xflip] == true && push!(axisargs[:style], "x dir=reverse")
d[:yflip] == true && push!(axisargs[:style], "y dir=reverse")
if d[:xscale] in (:log, :log2, :ln, :log10)
axisargs[:xmode] = "log"
if d[:xscale] == :log2
axisargs[:style] *= "log basis x=2,"
push!(axisargs[:style], "log basis x=2")
elseif d[:xscale] in (:log, :log10)
axisargs[:style] *= "log basis x=10,"
push!(axisargs[:style], "log basis x=10")
end
end
if d[:yscale] in (:log, :log2, :ln, :log10)
axisargs[:ymode] = "log"
if d[:yscale] == :log2
axisargs[:style] *= "log basis y=2,"
push!(axisargs[:style], "log basis y=2")
elseif d[:yscale] in (:log, :log10)
axisargs[:style] *= "log basis x=10,"
push!(axisargs[:style], "log basis x=10")
end
end
if d[:zscale] in (:log, :log2, :ln, :log10)
axisargs[:zmode] = "log"
if d[:zscale] == :log2
axisargs[:style] *= "log basis z=2,"
push!(axisargs[:style], "log basis z=2")
elseif d[:zscale] in (:log, :log10)
axisargs[:style] *= "log basis x=10,"
push!(axisargs[:style], "log basis x=10")
end
end
# Control background color
axisargs[:style] *= "axis background/.style={fill=$(_pgfplots_get_color(d, :background_color))},"
push!(axisargs[:style], "axis background/.style={fill=$(_pgfplots_get_color(d, :background_color))}")
# Control x/y-limits
if d[:xlims] !== :auto
axisargs[:xmin] = d[:xlims][1]
@ -339,11 +341,8 @@ function _pgfplots_get_axis_kwargs(d)
axisargs[:ymin] = d[:ylims][1]
axisargs[:ymax] = d[:ylims][2]
end
if d[:grid] == true
axisargs[:style] *= "grid = major,"
elseif d[:grid] == false
end
d[:grid] == true && push!(axisargs[:style], "grid = major")
if d[:aspect_ratio] == :equal || d[:aspect_ratio] == 1
axisargs[:axisEqual] = "true"
@ -352,6 +351,7 @@ function _pgfplots_get_axis_kwargs(d)
if ((d[:legend] != :none) || (d[:legend] != :best)) && (d[:legend] in keys(_pgfplots_legend_pos))
axisargs[:legendPos] = _pgfplots_legend_pos[d[:legend]]
end
axisargs[:style] = join(axisargs[:style], ',')
axisargs
end
@ -366,7 +366,8 @@ function _make_pgf_plot(plt::Plot{PGFPlotsBackend})
push!(os, _pgfplots_axis(plt_series))
end
axisargs =_pgfplots_get_axis_kwargs(plt.plotargs)
plt.o = PGFPlots.Axis([os...]; axisargs...)
w, h = map(px2mm, plt.plotargs[:size])
plt.o = PGFPlots.Axis([os...]; width = "$w mm", height = "$h mm", axisargs...)
end
function Base.writemime(io::IO, mime::MIME"image/svg+xml", plt::AbstractPlot{PGFPlotsBackend})