""" 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 = cgrad(: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 = cgrad.([: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"], titlelocation = :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, ], ), PlotExample( "Setting defaults and font arguments", "", [ quote begin using Plots default( titlefont = (20, "times"), legendfontsize = 18, guidefont = (18, :darkgreen), tickfont = (12, :orange), guide = "x", framestyle = :zerolines, yminorgrid = true ) plot( [sin, cos], -2π, 2π, label = ["sin(θ)" "cos(θ)"], title = "Trigonometric Functions", xlabel = "θ", linewidth = 2, legend = :outertopleft, ) end end, ], ), PlotExample( "Heatmap with DateTime axis", "", [ quote begin using Dates z = rand(5, 5) x = DateTime.(2016:2020) y = 1:5 heatmap(x, y, z) end end, ], ), PlotExample( "Linked axes", "", [ quote begin x = -5:0.1:5 plot(plot(x, x->x^2), plot(x, x->sin(x)), layout = 2, link = :y) end end, ], ), PlotExample( "Error bars and array type recipes", "", [ quote begin struct Measurement <: Number val::Float64 err::Float64 end value(m::Measurement) = m.val uncertainty(m::Measurement) = m.err @recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:Measurement} if !(get(plotattributes, :seriestype, :path) in [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]) error_sym = Symbol(plotattributes[:letter], :error) plotattributes[error_sym] = uncertainty.(m) end value.(m) end x = Measurement.(10sort(rand(10)), rand(10)) y = Measurement.(10sort(rand(10)), rand(10)) z = Measurement.(10sort(rand(10)), rand(10)) surf = Measurement.((1:10) .* (1:10)', rand(10,10)) plot( scatter(x, [x y], msw = 0), scatter(x, y, z, msw = 0), heatmap(x, y, surf), wireframe(x, y, surf), legend = :topleft ) end end, ], ), ] # Some constants for PlotDocs and PlotReferenceImages _animation_examples = [2, 31] _backend_skips = Dict( :gr => [25, 30], :pyplot => [2, 25, 30, 31], :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 => [ 2, # animation 6, # images 10, # histogram2d 16, # pgfplots thinks the upper panel is too small 22, # contourf 23, # pie 25, # @df 30, # @df 31, # animation 32, # spy 38, # histogram2d 45, # wireframe ], ) # --------------------------------------------------------------------------------- # 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