Plots.jl/src/examples.jl
Daniel Schwabeneder 3fb45764b2
Merge pull request #2471 from daschw/staticarrays
fix StaticArray plotting
2020-03-18 23:07:32 +01:00

967 lines
30 KiB
Julia
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
"""
mutable struct PlotExample
header::AbstractString
desc::AbstractString
exprs::Vector{Expr}
end
# the _examples we'll run for each
const _examples = PlotExample[
PlotExample(
"Lines",
"A simple line plot of the columns.",
[:(
begin
plot(Plots.fakedata(50, 5), w = 3)
end
)],
),
PlotExample(
"Functions, adding data, and animations",
"""
Plot multiple functions. You can also put the function first, or use the form `plot(f,
xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data:
`x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with
`push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available
to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the
animation.
""",
[:(
begin
p = plot([sin, cos], zeros(0), leg = false)
anim = Animation()
for x in range(0, stop = 10π, length = 100)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
end
)],
),
PlotExample(
"Parametric plots",
"Plot function pair (x(u), y(u)).",
[
:(
begin
plot(
sin,
x -> sin(2x),
0,
2π,
line = 4,
leg = false,
fill = (0, :orange),
)
end
),
],
),
PlotExample(
"Colors",
"""
Access predefined palettes (or build your own with the `colorscheme` method).
Line/marker colors are auto-generated from the plot's palette, unless overridden. Set
the `z` argument to turn on series gradients.
""",
[
:(
begin
y = rand(100)
plot(
0:10:100,
rand(11, 4),
lab = "lines",
w = 3,
palette = :grays,
fill = 0,
α = 0.6,
)
scatter!(
y,
zcolor = abs.(y .- 0.5),
m = (:heat, 0.8, Plots.stroke(1, :green)),
ms = 10 * abs.(y .- 0.5) .+ 4,
lab = "grad",
)
end
),
],
),
PlotExample(
"Global",
"""
Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow
you to pass a tuple or value which will be mapped to the relevant args automatically.
The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during
the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`,
`yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`
""",
[
:(
begin
using Statistics
y = rand(20, 3)
plot(
y,
xaxis = ("XLABEL", (-5, 30), 0:2:20, :flip),
background_color = RGB(0.2, 0.2, 0.2),
leg = false,
)
hline!(
mean(y, dims = 1) + rand(1, 3),
line = (4, :dash, 0.6, [:lightgreen :green :darkgreen]),
)
vline!([5, 10])
title!("TITLE")
yaxis!("YLABEL", :log10)
end
),
],
),
# PlotExample("Two-axis",
# "Use the `axis` arguments.",
# [
# :(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT", xlabel="X", title="TITLE"))
# ]),
PlotExample(
"Images",
"Plot an image. y-axis is set to flipped",
[
:(
begin
import FileIO
path =
download("http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png")
img = FileIO.load(path)
plot(img)
end
),
],
),
PlotExample(
"Arguments",
"""
Plot multiple series with different numbers of points. Mix arguments that apply to all
series (marker/markersize) with arguments unique to each series (colors). Special
arguments `line`, `marker`, and `fill` will automatically figure out what arguments to
set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with
`line`.) Note that we pass a matrix of colors, and this applies the colors to each
series.
""",
[
:(
begin
ys = Vector[rand(10), rand(20)]
plot(
ys,
color = [:black :orange],
line = (:dot, 4),
marker = ([:hex :d], 12, 0.8, Plots.stroke(3, :gray)),
)
end
),
],
),
PlotExample(
"Build plot in pieces",
"Start with a base plot...",
[:(
begin
plot(rand(100) / 3, reg = true, fill = (0, :green))
end
)],
),
PlotExample(
"",
"and add to it later.",
[:(
begin
scatter!(rand(100), markersize = 6, c = :orange)
end
)],
),
PlotExample(
"Histogram2D",
"",
[:(
begin
histogram2d(randn(10000), randn(10000), nbins = 20)
end
)],
),
PlotExample(
"Line types",
"",
[
:(
begin
linetypes = [:path :steppre :steppost :sticks :scatter]
n = length(linetypes)
x = Vector[sort(rand(20)) for i = 1:n]
y = rand(20, n)
plot(
x,
y,
line = (linetypes, 3),
lab = map(string, linetypes),
ms = 15,
)
end
),
],
),
PlotExample(
"Line styles",
"",
[
:(
begin
styles = filter(
s -> s in Plots.supported_styles(),
[:solid, :dash, :dot, :dashdot, :dashdotdot],
)
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20, n), dims = 1)
plot(
y,
line = (5, styles),
label = map(string, styles),
legendtitle = "linestyle",
)
end
),
],
),
PlotExample(
"Marker types",
"",
[
:(
begin
markers = filter(
m -> m in Plots.supported_markers(),
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
),
],
),
PlotExample(
"Bar",
"`x` is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)",
[:(
begin
bar(randn(99))
end
)],
),
PlotExample(
"Histogram",
"",
[
:(
begin
histogram(
randn(1000),
bins = :scott,
weights = repeat(1:5, outer = 200),
)
end
),
],
),
PlotExample(
"Subplots",
"""
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate
arbitrarily complex subplot layouts.
""",
[
:(
begin
l = @layout([a{0.1h}; b [c; d e]])
plot(
randn(100, 5),
layout = l,
t = [:line :histogram :scatter :steppre :bar],
leg = false,
ticks = nothing,
border = :none,
)
end
),
],
),
PlotExample(
"Adding to subplots",
"""
Note here the automatic grid layout, as well as the order in which new series are added
to the plots.
""",
[
:(
begin
plot(
Plots.fakedata(100, 10),
layout = 4,
palette = [:grays :blues :heat :lightrainbow],
bg_inside = [:orange :pink :darkblue :black],
)
end
),
],
),
PlotExample("", "", [:(
begin
using Random
Random.seed!(111)
plot!(Plots.fakedata(100, 10))
end
)]),
PlotExample(
"Open/High/Low/Close",
"""
Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y`
argument. This uses recipes to first convert the tuples to OHLC objects, and
subsequently create a :path series with the appropriate line segments.
""",
[
:(
begin
n = 20
hgt = rand(n) .+ 1
bot = randn(n)
openpct = rand(n)
closepct = rand(n)
y = OHLC[
(
openpct[i] * hgt[i] + bot[i],
bot[i] + hgt[i],
bot[i],
closepct[i] * hgt[i] + bot[i],
)
for i = 1:n
]
ohlc(y)
end
),
],
),
PlotExample(
"Annotations",
"""
The `annotations` keyword is used for text annotations in data-coordinates. Pass in a
tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(;
annotation=ann)`. Series annotations are used for annotating individual data points.
They require only the annotation... x/y values are computed. A `PlotText` object can be
build with the method `text(string, attr...)`, which wraps font and color attributes.
""",
[
:(
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
),
],
),
PlotExample(
"Custom Markers",
"""A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported
backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and
the size is expected to be rougly the area of the unit circle.
""",
[
:(
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
),
],
),
PlotExample(
"Contours",
"""
Any value for fill works here. We first build a filled contour from a function, then an
unfilled contour from a matrix.
""",
[:(
begin
x = 1:0.5:20
y = 1:0.5:10
f(x, y) = (3x + y^2) * abs(sin(x) + cos(y))
X = repeat(reshape(x, 1, :), length(y), 1)
Y = repeat(y, 1, length(x))
Z = map(f, X, Y)
p1 = contour(x, y, f, fill = true)
p2 = contour(x, y, Z)
plot(p1, p2)
end
)],
),
PlotExample(
"Pie",
"",
[:(
begin
x = ["Nerds", "Hackers", "Scientists"]
y = [0.4, 0.35, 0.25]
pie(x, y, title = "The Julia Community", l = 0.5)
end
)],
),
PlotExample(
"3D",
"",
[
:(
begin
n = 100
ts = range(0, stop = 8π, length = n)
x = ts .* map(cos, ts)
y = 0.1ts .* map(sin, ts)
z = 1:n
plot(
x,
y,
z,
zcolor = reverse(z),
m = (10, 0.8, :blues, Plots.stroke(0)),
leg = false,
cbar = true,
w = 5,
)
plot!(zeros(n), zeros(n), 1:n, w = 10)
end
),
],
),
PlotExample(
"DataFrames",
"Plot using DataFrame column symbols.",
[
:(using StatsPlots), # can't be inside begin block because @df gets expanded first
:(
begin
import RDatasets
iris = RDatasets.dataset("datasets", "iris")
@df iris scatter(
:SepalLength,
:SepalWidth,
group = :Species,
title = "My awesome plot",
xlabel = "Length",
ylabel = "Width",
marker = (0.5, [:cross :hex :star7], 12),
bg = RGB(0.2, 0.2, 0.2),
)
end
),
],
),
PlotExample(
"Groups and Subplots",
"",
[
:(
begin
group = rand(map(i -> "group $i", 1:4), 100)
plot(
rand(100),
layout = @layout([a b; c]),
group = group,
linetype = [:bar :scatter :steppre],
linecolor = :match,
)
end
),
],
),
PlotExample(
"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
)],
),
PlotExample(
"Heatmap, categorical axes, and aspect_ratio",
"",
[:(
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, :))
heatmap(xs, ys, z, aspect_ratio = 1)
end
)],
),
PlotExample(
"Layouts, margins, label rotation, title location",
"",
[
:(
begin
using Plots.PlotMeasures # for Measures, e.g. mm and px
plot(
rand(100, 6),
layout = @layout([a b; c]),
title = ["A" "B" "C"],
title_location = :left,
left_margin = [20mm 0mm],
bottom_margin = 10px,
xrotation = 60,
)
end
),
],
),
PlotExample(
"Boxplot and Violin series recipes",
"",
[
:(using StatsPlots), # can't be inside begin block because @df gets expanded first
:(
begin
import RDatasets
singers = RDatasets.dataset("lattice", "singer")
@df singers violin(
:VoicePart,
:Height,
line = 0,
fill = (0.2, :blue),
)
@df singers boxplot!(
:VoicePart,
:Height,
line = (2, :black),
fill = (0.3, :orange),
)
end
),
],
),
PlotExample(
"Animation with subplots",
"The `layout` macro can be used to create an animation with subplots.",
[
:(
begin
l = @layout([[a; b] c])
p = plot(
plot([sin, cos], 1, leg = false),
scatter([atan, cos], 1, leg = false),
plot(log, 1, xlims = (1, 10π), ylims = (0, 5), leg = false),
layout = l,
)
anim = Animation()
for x in range(1, stop = 10π, length = 100)
plot(push!(
p,
x,
Float64[sin(x), cos(x), atan(x), cos(x), log(x)],
))
frame(anim)
end
end
),
],
),
PlotExample(
"Spy",
"""
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
various different nonzero values, a colorbar is added. The colorbar can be disabled with
`legend = nothing`.
""",
[
:(
begin
using SparseArrays
a = spdiagm(
0 => ones(50),
1 => ones(49),
-1 => ones(49),
10 => ones(40),
-10 => ones(40),
)
b = spdiagm(
0 => 1:50,
1 => 1:49,
-1 => 1:49,
10 => 1:40,
-10 => 1:40,
)
plot(
spy(a),
spy(b),
title = ["Unique nonzeros" "Different nonzeros"],
)
end
),
],
),
PlotExample(
"Magic grid argument",
"""
The grid lines can be modified individually for each axis with the magic `grid` argument.
""",
[
:(
begin
x = rand(10)
p1 = plot(x, title = "Default looks")
p2 = plot(
x,
grid = (:y, :olivedrab, :dot, 1, 0.9),
title = "Modified y grid",
)
p3 = plot(deepcopy(p2), title = "Add x grid")
xgrid!(p3, :on, :cadetblue, 2, :dashdot, 0.4)
plot(
p1,
p2,
p3,
layout = (1, 3),
label = "",
fillrange = 0,
fillalpha = 0.3,
)
end
),
],
),
PlotExample(
"Framestyle",
"""
The style of the frame/axes of a (sub)plot can be changed with the `framestyle`
attribute. The default framestyle is `:axes`.
""",
[
:(
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,
)
end
),
],
),
PlotExample(
"Lines and markers with varying colors",
"""
You can use the `line_z` and `marker_z` properties to associate a color with
each line segment or marker in the plot.
""",
[
:(
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 = +,
color = :bluesreds,
legend = false,
)
plot(p1, p2)
end
),
],
),
PlotExample(
"Portfolio Composition maps",
"""
see: http://stackoverflow.com/a/37732384/5075246
""",
[
:(
begin
using Random
Random.seed!(111)
tickers = ["IBM", "Google", "Apple", "Intel"]
N = 10
D = length(tickers)
weights = rand(N, D)
weights ./= sum(weights, dims = 2)
returns = sort!((1:N) + D * randn(N))
portfoliocomposition(
weights,
returns,
labels = permutedims(tickers),
)
end
),
],
),
PlotExample(
"Ribbons",
"""
Ribbons can be added to lines via the `ribbon` keyword;
you can pass a tuple of arrays (upper and lower bounds),
a single Array (for symmetric ribbons), a Function, or a number.
""",
[
:(
begin
plot(
plot(
0:10;
ribbon = (LinRange(0, 2, 11), LinRange(0, 1, 11)),
),
plot(0:10; ribbon = 0:0.5:5),
plot(0:10; ribbon = sqrt),
plot(0:10; ribbon = 1),
)
end
),
],
),
PlotExample(
"Histogram2D (complex values)",
"",
[
:(
begin
n = 10_000
x = exp.(0.1 * randn(n) .+ randn(n) .* (im))
histogram2d(
x,
nbins = (20, 40),
show_empty_bins = true,
normed = true,
aspect_ratio = 1,
)
end
),
],
),
PlotExample(
"Unconnected lines using `missing` or `NaN`",
"""
Missing values and non-finite values, including `NaN`, are not plotted.
Instead, lines are separated into segments at these values.
""",
[
:(
begin
x, y = [1, 2, 2, 1, 1], [1, 2, 1, 2, 1]
plot(
plot([rand(5); NaN; rand(5); NaN; rand(5)]),
plot([1, missing, 2, 3], marker = true),
plot([x; NaN; x .+ 2], [y; NaN; y .+ 1], arrow = 2),
plot(
[1, 2 + 3im, Inf, 4im, 3, -Inf * im, 0, 3 + 3im],
marker = true,
),
legend = false,
)
end
),
],
),
PlotExample(
"Lens",
"A lens lets you easily magnify a region of a plot. x and y coordinates refer to the to be magnified region and the via the `inset` keyword the subplot index and the bounding box (in relative coordinates) of the inset plot with the magnified plot can be specified. Additional attributes count for the inset plot.",
[
quote
begin
plot(
[(0, 0), (0, 0.9), (1, 0.9), (2, 1), (3, 0.9), (80, 0)],
legend = :outertopright,
)
plot!([(0, 0), (0, 0.9), (2, 0.9), (3, 1), (4, 0.9), (80, 0)])
plot!([(0, 0), (0, 0.9), (3, 0.9), (4, 1), (5, 0.9), (80, 0)])
plot!([(0, 0), (0, 0.9), (4, 0.9), (5, 1), (6, 0.9), (80, 0)])
lens!(
[1, 6],
[0.9, 1.1],
inset = (1, bbox(0.5, 0.0, 0.4, 0.4)),
)
end
end,
],
),
PlotExample(
"Array Types",
"Plots supports different `Array` types that follow the `AbstractArray` interface, like `StaticArrays` and `OffsetArrays.`",
[
quote
begin
using StaticArrays, OffsetArrays
sv = SVector{10}(rand(10))
ov = OffsetVector(rand(10), -2)
plot([sv, ov], label = ["StaticArray" "OffsetArray"])
end
end,
],
),
]
# Some constants for PlotDocs and PlotReferenceImages
_animation_examples = [2, 30]
_backend_skips = Dict(
:gr => [25, 30],
:pyplot => [25, 30],
:plotlyjs => [2, 21, 24, 25, 30, 31],
:plotly => [2, 21, 24, 25, 30, 31],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30, 31, 34, 37, 38, 39],
:pgfplotsx => [ 6, # images
10, # histogram2d
22, # contourf
23, # pie
32, # spy
38, # histogram2d
] )
# ---------------------------------------------------------------------------------
# make and display one plot
function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
Plots._debugMode.on = debug
@info("Testing plot: $pkgname:$idx:$(_examples[idx].header)")
backend(pkgname)
backend()
# prevent leaking variables (esp. functions) directly into Plots namespace
m = Module(:PlotExampleModule)
Base.eval(m, :(using Plots))
map(exprs -> Base.eval(m, exprs), _examples[idx].exprs)
plt = current()
if disp
gui(plt)
end
plt
end
# generate all plots and create a dict mapping idx --> plt
"""
test_examples(pkgname[, idx]; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing
Run the `idx` test example for a given backend, or all examples if `idx`
is not specified.
"""
function test_examples(
pkgname::Symbol;
debug = false,
disp = true,
sleep = nothing,
skip = [],
only = nothing,
)
Plots._debugMode.on = debug
plts = Dict()
for i in eachindex(_examples)
only !== nothing && !(i in only) && continue
i in skip && continue
try
plt = test_examples(pkgname, i, debug = debug, disp = disp)
plts[i] = plt
catch ex
# TODO: put error info into markdown?
@warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
end
if sleep !== nothing
Base.sleep(sleep)
end
end
plts
end