Merge branch 'master' into add-stride

This commit is contained in:
Jack Devine 2017-09-03 13:04:32 +12:00 committed by GitHub
commit c7eb22021f
30 changed files with 642 additions and 181 deletions

13
NEWS.md
View File

@ -11,14 +11,23 @@
--- ---
## (current master) ## (current master)
## 0.12.2 ## 0.12.3
- new grid line style defaults
- `grid` is now an axis attribute and a magic argument: it is now possible to modify the grid line style, alpha and line width
- Enforce plot order in user recipes
- import `plot!` from RecipesBase
- GR no longer automatically handles _ and ^ in texts
- fix GR colorbar for scatter plots
#### 0.12.2
- fix an issue with Juno/PlotlyJS compatibility on new installations - fix an issue with Juno/PlotlyJS compatibility on new installations
- fix markers not showing up in seriesrecipes using :scatter - fix markers not showing up in seriesrecipes using :scatter
- don't use pywrap in the pyplot backend - don't use pywrap in the pyplot backend
- improve the bottom margin for the gr backend - improve the bottom margin for the gr backend
## 0.12.1 #### 0.12.1
- fix deprecation warnings - fix deprecation warnings
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays - switch from FixedSizeArrays to StaticArrays.FixedSizeArrays

View File

@ -1,6 +1,7 @@
# Plots # Plots
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl) [![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/tbreloff/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/tbreloff/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) --> <!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) --> <!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->

View File

@ -1,4 +1,4 @@
julia 0.6-pre julia 0.6
RecipesBase 0.2.0 RecipesBase 0.2.0
PlotUtils 0.4.1 PlotUtils 0.4.1

View File

@ -1,7 +1,13 @@
environment: environment:
matrix: matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe" - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe" - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
matrix:
allow_failures:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" #check and address
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"

View File

@ -8,7 +8,7 @@ import StaticArrays
using StaticArrays.FixedSizeArrays using StaticArrays.FixedSizeArrays
@reexport using RecipesBase @reexport using RecipesBase
import RecipesBase: plot, animate import RecipesBase: plot, plot!, animate
using Base.Meta using Base.Meta
@reexport using PlotUtils @reexport using PlotUtils
@reexport using PlotThemes @reexport using PlotThemes
@ -52,6 +52,8 @@ export
yflip!, yflip!,
xaxis!, xaxis!,
yaxis!, yaxis!,
xgrid!,
ygrid!,
xlims, xlims,
ylims, ylims,
@ -186,33 +188,65 @@ include("output.jl")
@shorthands quiver @shorthands quiver
@shorthands curves @shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing) pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing) pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d) plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d) plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...) title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...) xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...) ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...) xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...) ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...) zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...) xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...) ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...) zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
"Set xticks for an existing plot"
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...) xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...) yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}( xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}( yticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...) annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...) annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...) xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...) yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...) xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...) yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
let PlotOrSubplot = Union{Plot, Subplot} let PlotOrSubplot = Union{Plot, Subplot}
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...) title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
@ -230,6 +264,8 @@ let PlotOrSubplot = Union{Plot, Subplot}
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot, yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...) annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...) annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...) xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)

View File

@ -1,4 +1,4 @@
"Represents an animation object"
immutable Animation immutable Animation
dir::String dir::String
frames::Vector{String} frames::Vector{String}
@ -9,6 +9,11 @@ function Animation()
Animation(tmpdir, String[]) Animation(tmpdir, String[])
end end
"""
frame(animation[, plot])
Add a plot (the current plot if not specified) to an existing animation
"""
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current()) function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
i = length(anim.frames) + 1 i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i) filename = @sprintf("%06d.png", i)
@ -81,7 +86,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString;
catch err catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`. ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
You may also need to install the imagemagick c++ library through your operating system. You may also need to install the imagemagick c++ library through your operating system.
Will try ffmpeg, but it's lower quality...)""") Will try ffmpeg, but it's lower quality...)""")
# low quality # low quality

View File

@ -21,7 +21,7 @@ const _arg_desc = KW(
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)", :markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.", :markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.", :markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto. For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`", :bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
:smooth => "Bool. Add a regression line?", :smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.", :group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension", :x => "Various. Input data. First Dimension",
@ -40,7 +40,7 @@ const _arg_desc = KW(
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.", :ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.", :quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.", :arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a PDF with integral of 1) and :density (only normalize in respect to bin sizes).", :normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.", :weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.", :contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.", :match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
@ -76,7 +76,6 @@ const _arg_desc = KW(
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).", :background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.", :foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.", :foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", :foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.", :color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)", :legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
@ -84,7 +83,6 @@ const _arg_desc = KW(
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)", :colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.", :clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.", :legendfont => "Font. Font of legend items.",
:grid => "Bool. Show the grid lines?",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.", :annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'", :projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.", :aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
@ -95,6 +93,7 @@ const _arg_desc = KW(
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.", :bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.", :subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.", :colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
# axis args # axis args
:guide => "String. Axis guide (label).", :guide => "String. Axis guide (label).",
@ -111,5 +110,9 @@ const _arg_desc = KW(
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.", :foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).", :foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).", :mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
) )

View File

@ -80,9 +80,13 @@ const _typeAliases = Dict{Symbol,Symbol}(
add_non_underscore_aliases!(_typeAliases) add_non_underscore_aliases!(_typeAliases)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins) const _histogram_like = [:histogram, :barhist, :barbins]
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost) const _line_like = [:line, :path, :steppre, :steppost]
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image) const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
like_histogram(seriestype::Symbol) = seriestype in _histogram_like
like_line(seriestype::Symbol) = seriestype in _line_like
like_surface(seriestype::Symbol) = seriestype in _surface_like
is3d(seriestype::Symbol) = seriestype in _3dTypes is3d(seriestype::Symbol) = seriestype in _3dTypes
is3d(series::Series) = is3d(series.d) is3d(series::Series) = is3d(series.d)
@ -163,6 +167,32 @@ const _scaleAliases = Dict{Symbol,Symbol}(
:log => :log10, :log => :log10,
) )
const _allGridSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on,
:none, :off,]
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
hasgrid(arg::Void, letter) = false
hasgrid(arg::Bool, letter) = arg
function hasgrid(arg::Symbol, letter)
if arg in _allGridSyms
arg in (:all, :both, :on) || contains(string(arg), string(letter))
else
warn("Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead.")
true
end
end
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allFramestyles = [:box, :semi, :axes, :grid, :none]
const _framestyleAliases = Dict{Symbol, Symbol}(
:frame => :box,
:border => :box,
:on => :box,
:transparent => :semi,
:semitransparent => :semi,
)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
const _series_defaults = KW( const _series_defaults = KW(
@ -172,7 +202,7 @@ const _series_defaults = KW(
:seriestype => :path, :seriestype => :path,
:linestyle => :solid, :linestyle => :solid,
:linewidth => :auto, :linewidth => :auto,
:linecolor => :match, :linecolor => :auto,
:linealpha => nothing, :linealpha => nothing,
:fillrange => nothing, # ribbons, areas, etc :fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match, :fillcolor => :match,
@ -248,7 +278,6 @@ const _subplot_defaults = KW(
:background_color_inside => :match, # background inside grid :background_color_inside => :match, # background inside grid
:foreground_color_subplot => :match, # default for other fg colors... match takes plot default :foreground_color_subplot => :match, # default for other fg colors... match takes plot default
:foreground_color_legend => :match, # foreground of legend :foreground_color_legend => :match, # foreground of legend
:foreground_color_grid => :match, # grid color
:foreground_color_title => :match, # title color :foreground_color_title => :match, # title color
:color_palette => :auto, :color_palette => :auto,
:legend => :best, :legend => :best,
@ -256,7 +285,6 @@ const _subplot_defaults = KW(
:colorbar => :legend, :colorbar => :legend,
:clims => :auto, :clims => :auto,
:legendfont => font(8), :legendfont => font(8),
:grid => true,
:annotations => [], # annotation tuples... list of (x,y,annotation) :annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d :projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal :aspect_ratio => :none, # choose from :none or :equal
@ -267,6 +295,7 @@ const _subplot_defaults = KW(
:bottom_margin => :match, :bottom_margin => :match,
:subplot_index => -1, :subplot_index => -1,
:colorbar_title => "", :colorbar_title => "",
:framestyle => :axes,
) )
const _axis_defaults = KW( const _axis_defaults = KW(
@ -286,6 +315,11 @@ const _axis_defaults = KW(
:discrete_values => [], :discrete_values => [],
:formatter => :auto, :formatter => :auto,
:mirror => false, :mirror => false,
:grid => true,
:foreground_color_grid => :match, # grid color
:gridalpha => 0.1,
:gridstyle => :solid,
:gridlinewidth => 0.5,
) )
const _suppress_warnings = Set{Symbol}([ const _suppress_warnings = Set{Symbol}([
@ -403,7 +437,7 @@ add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_co
add_aliases(:foreground_color_axis, :fg_axis, :fgaxis, :fgcolor_axis, :fg_color_axis, :foreground_axis, add_aliases(:foreground_color_axis, :fg_axis, :fgaxis, :fgcolor_axis, :fg_color_axis, :foreground_axis,
:foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor) :foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor)
add_aliases(:foreground_color_border, :fg_border, :fgborder, :fgcolor_border, :fg_color_border, :foreground_border, add_aliases(:foreground_color_border, :fg_border, :fgborder, :fgcolor_border, :fg_color_border, :foreground_border,
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor, :border) :foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor)
add_aliases(:foreground_color_text, :fg_text, :fgtext, :fgcolor_text, :fg_color_text, :foreground_text, add_aliases(:foreground_color_text, :fg_text, :fgtext, :fgcolor_text, :fg_color_text, :foreground_text,
:foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor) :foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor)
add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_color_guide, :foreground_guide, add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_color_guide, :foreground_guide,
@ -415,6 +449,7 @@ add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity) add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity) add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity) add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
# series attributes # series attributes
add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt) add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt)
@ -471,6 +506,9 @@ add_aliases(:html_output_format, :format, :fmt, :html_format)
add_aliases(:orientation, :direction, :dir) add_aliases(:orientation, :direction, :dir)
add_aliases(:inset_subplots, :inset, :floating) add_aliases(:inset_subplots, :inset, :floating)
add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str) add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str)
add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw)
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border)
# add all pluralized forms to the _keyAliases dict # add all pluralized forms to the _keyAliases dict
@ -490,7 +528,6 @@ end
`default(; kw...)` will set the current default value for each key/value pair `default(; kw...)` will set the current default value for each key/value pair
`default(d, key)` returns the key from d if it exists, otherwise `default(key)` `default(d, key)` returns the key from d if it exists, otherwise `default(key)`
""" """
function default(k::Symbol) function default(k::Symbol)
k = get(_keyAliases, k, k) k = get(_keyAliases, k, k)
for defaults in _all_defaults for defaults in _all_defaults
@ -647,6 +684,36 @@ function processFillArg(d::KW, arg)
return return
end end
function processGridArg!(d::KW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
d[Symbol(letter, :grid)] = hasgrid(arg, letter)
elseif allStyles(arg)
d[Symbol(letter, :gridstyle)] = arg
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[Symbol(letter, :gridlinewidth)] = arg.width)
arg.color == nothing || (d[Symbol(letter, :foreground_color_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color))
arg.alpha == nothing || (d[Symbol(letter, :gridalpha)] = arg.alpha)
arg.style == nothing || (d[Symbol(letter, :gridstyle)] = arg.style)
# linealpha
elseif allAlphas(arg)
d[Symbol(letter, :gridalpha)] = arg
# linewidth
elseif allReals(arg)
d[Symbol(letter, :gridlinewidth)] = arg
# color
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
warn("Skipped grid arg $arg.")
end
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape) _replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes) _replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
_replace_markershape(shape) = shape _replace_markershape(shape) = shape
@ -668,6 +735,7 @@ function preprocessArgs!(d::KW)
if haskey(d, :axis) && d[:axis] in (:none, nothing, false) if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
d[:ticks] = nothing d[:ticks] = nothing
d[:foreground_color_border] = RGBA(0,0,0,0) d[:foreground_color_border] = RGBA(0,0,0,0)
d[:foreground_color_axis] = RGBA(0,0,0,0)
d[:grid] = false d[:grid] = false
delete!(d, :axis) delete!(d, :axis)
end end
@ -690,6 +758,22 @@ function preprocessArgs!(d::KW)
end end
end end
# handle grid args common to all axes
args = pop!(d, :grid, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processGridArg!(d, arg, letter)
end
end
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :grid)
args = pop!(d, gridsym, ())
for arg in wraptuple(args)
processGridArg!(d, arg, letter)
end
end
# handle line args # handle line args
for arg in wraptuple(pop!(d, :line, ())) for arg in wraptuple(pop!(d, :line, ()))
processLineArg(d, arg) processLineArg(d, arg)
@ -754,6 +838,11 @@ function preprocessArgs!(d::KW)
d[:colorbar] = convertLegendValue(d[:colorbar]) d[:colorbar] = convertLegendValue(d[:colorbar])
end end
# framestyle
if haskey(d, :framestyle) && haskey(_framestyleAliases, d[:framestyle])
d[:framestyle] = _framestyleAliases[d[:framestyle]]
end
# warnings for moved recipes # warnings for moved recipes
st = get(d, :seriestype, :path) st = get(d, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots) if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
@ -773,21 +862,29 @@ end
# this is when given a vector-type of values to group by # this is when given a vector-type of values to group by
function extractGroupArgs(v::AVec, args...) function extractGroupArgs(v::AVec, args...; legendEntry = string)
groupLabels = sort(collect(unique(v))) groupLabels = sort(collect(unique(v)))
n = length(groupLabels) n = length(groupLabels)
if n > 100 if n > 100
warn("You created n=$n groups... Is that intended?") warn("You created n=$n groups... Is that intended?")
end end
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels] groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
GroupBy(map(string, groupLabels), groupIds) GroupBy(map(legendEntry, groupLabels), groupIds)
end end
legendEntryFromTuple(ns::Tuple) = string(("$n " for n in ns)...)
# this is when given a tuple of vectors of values to group by
function extractGroupArgs(vs::Tuple, args...)
(vs == ()) && return GroupBy([""], [1:size(args[1],1)])
v = collect(zip(vs...))
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
# expecting a mapping of "group label" to "group indices" # expecting a mapping of "group label" to "group indices"
function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...) function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...)
groupLabels = sortedkeys(idxmap) groupLabels = sortedkeys(idxmap)
groupIds = VecI[collect(idxmap[k]) for k in groupLabels] groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
GroupBy(groupLabels, groupIds) GroupBy(groupLabels, groupIds)
end end
@ -945,7 +1042,6 @@ const _match_map = KW(
:background_color_legend => :background_color_subplot, :background_color_legend => :background_color_subplot,
:background_color_inside => :background_color_subplot, :background_color_inside => :background_color_subplot,
:foreground_color_legend => :foreground_color_subplot, :foreground_color_legend => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_title => :foreground_color_subplot, :foreground_color_title => :foreground_color_subplot,
:left_margin => :margin, :left_margin => :margin,
:top_margin => :margin, :top_margin => :margin,
@ -959,6 +1055,7 @@ const _match_map2 = KW(
:foreground_color_subplot => :foreground_color, :foreground_color_subplot => :foreground_color,
:foreground_color_axis => :foreground_color_subplot, :foreground_color_axis => :foreground_color_subplot,
:foreground_color_border => :foreground_color_subplot, :foreground_color_border => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_guide => :foreground_color_subplot, :foreground_color_guide => :foreground_color_subplot,
:foreground_color_text => :foreground_color_subplot, :foreground_color_text => :foreground_color_subplot,
) )
@ -1093,7 +1190,6 @@ function _update_subplot_colors(sp::Subplot)
# foreground colors # foreground colors
color_or_nothing!(sp.attr, :foreground_color_subplot) color_or_nothing!(sp.attr, :foreground_color_subplot)
color_or_nothing!(sp.attr, :foreground_color_legend) color_or_nothing!(sp.attr, :foreground_color_legend)
color_or_nothing!(sp.attr, :foreground_color_grid)
color_or_nothing!(sp.attr, :foreground_color_title) color_or_nothing!(sp.attr, :foreground_color_title)
return return
end end
@ -1145,6 +1241,7 @@ function _update_axis_colors(axis::Axis)
color_or_nothing!(axis.d, :foreground_color_border) color_or_nothing!(axis.d, :foreground_color_border)
color_or_nothing!(axis.d, :foreground_color_guide) color_or_nothing!(axis.d, :foreground_color_guide)
color_or_nothing!(axis.d, :foreground_color_text) color_or_nothing!(axis.d, :foreground_color_text)
color_or_nothing!(axis.d, :foreground_color_grid)
return return
end end
@ -1250,12 +1347,14 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
# update other colors # update other colors
for s in (:line, :marker, :fill) for s in (:line, :marker, :fill)
csym, asym = Symbol(s,:color), Symbol(s,:alpha) csym, asym = Symbol(s,:color), Symbol(s,:alpha)
d[csym] = if d[csym] == :match d[csym] = if d[csym] == :auto
plot_color(if has_black_border_for_default(d[:seriestype]) && s == :line plot_color(if has_black_border_for_default(d[:seriestype]) && s == :line
sp[:foreground_color_subplot] sp[:foreground_color_subplot]
else else
d[:seriescolor] d[:seriescolor]
end, d[asym]) end, d[asym])
elseif d[csym] == :match
plot_color(d[:seriescolor], d[asym])
else else
getSeriesRGBColor(d[csym], d[asym], sp, plotIndex) getSeriesRGBColor(d[csym], d[asym], sp, plotIndex)
end end

View File

@ -181,15 +181,27 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
end end
# get a list of well-laid-out ticks # get a list of well-laid-out ticks
scaled_ticks = if ticks == nothing if ticks == nothing
optimize_ticks( scaled_ticks = optimize_ticks(
sf(amin), sf(amin),
sf(amax); sf(amax);
k_min = 5, # minimum number of ticks k_min = 4, # minimum number of ticks
k_max = 8, # maximum number of ticks k_max = 8, # maximum number of ticks
)[1] )[1]
elseif typeof(ticks) <: Int
scaled_ticks, viewmin, viewmax = optimize_ticks(
sf(amin),
sf(amax);
k_min = ticks, # minimum number of ticks
k_max = ticks, # maximum number of ticks
k_ideal = ticks,
# `strict_span = false` rewards cases where the span of the
# chosen ticks is not too much bigger than amin - amax:
strict_span = false,
)
axis[:lims] = map(invscalefunc(scale), (viewmin, viewmax))
else else
map(sf, filter(t -> amin <= t <= amax, ticks)) scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end end
unscaled_ticks = map(invscalefunc(scale), scaled_ticks) unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
@ -216,7 +228,7 @@ end
# return (continuous_values, discrete_values) for the ticks on this axis # return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(axis::Axis) function get_ticks(axis::Axis)
ticks = axis[:ticks] ticks = _transform_ticks(axis[:ticks])
ticks in (nothing, false) && return nothing ticks in (nothing, false) && return nothing
dvals = axis[:discrete_values] dvals = axis[:discrete_values]
@ -226,7 +238,7 @@ function get_ticks(axis::Axis)
elseif ticks == :auto elseif ticks == :auto
# compute optimal ticks and labels # compute optimal ticks and labels
optimal_ticks_and_labels(axis) optimal_ticks_and_labels(axis)
elseif typeof(ticks) <: AVec elseif typeof(ticks) <: Union{AVec, Int}
# override ticks, but get the labels # override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks) optimal_ticks_and_labels(axis, ticks)
elseif typeof(ticks) <: NTuple{2, Any} elseif typeof(ticks) <: NTuple{2, Any}
@ -246,6 +258,10 @@ function get_ticks(axis::Axis)
end end
end end
_transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@ -490,38 +506,46 @@ function axis_drawing_info(sp::Subplot)
ymin, ymax = axis_limits(yaxis) ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis) xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis) yticks = get_ticks(yaxis)
spine_segs = Segments(2) xaxis_segs = Segments(2)
grid_segs = Segments(2) yaxis_segs = Segments(2)
xgrid_segs = Segments(2)
ygrid_segs = Segments(2)
xborder_segs = Segments(2)
yborder_segs = Segments(2)
if !(xaxis[:ticks] in (nothing, false)) if !(sp[:framestyle] == :none)
f = scalefunc(yaxis[:scale]) # xaxis
invf = invscalefunc(yaxis[:scale]) sp[:framestyle] == :grid || push!(xaxis_segs, (xmin,ymin), (xmax,ymin)) # bottom spine / xaxis
t1 = invf(f(ymin) + 0.015*(f(ymax)-f(ymin))) sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin,ymax), (xmax,ymax)) # top spine
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin))) if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
t1 = invf(f(ymin) + 0.015*(f(ymax)-f(ymin)))
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin)))
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine for xtick in xticks[1]
# push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine push!(xaxis_segs, (xtick, ymin), (xtick, t1)) # bottom tick
for xtick in xticks[1] # sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick xaxis[:grid] && push!(xgrid_segs, (xtick, t1), (xtick, t2)) # vertical grid
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid end
# push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick end
# yaxis
sp[:framestyle] == :grid || push!(yaxis_segs, (xmin,ymin), (xmin,ymax)) # left spine / yaxis
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (xmax,ymin), (xmax,ymax)) # right spine
if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
t1 = invf(f(xmin) + 0.015*(f(xmax)-f(xmin)))
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
for ytick in yticks[1]
push!(yaxis_segs, (xmin, ytick), (t1, ytick)) # left tick
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
end
end end
end end
if !(yaxis[:ticks] in (nothing, false)) xticks, yticks, xaxis_segs, yaxis_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
t1 = invf(f(xmin) + 0.015*(f(xmax)-f(xmin)))
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
# push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
for ytick in yticks[1]
push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick
push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
# push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
end
end
xticks, yticks, spine_segs, grid_segs
end end

View File

@ -6,7 +6,10 @@ const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[] const _backends = Symbol[]
const _initialized_backends = Set{Symbol}() const _initialized_backends = Set{Symbol}()
"Returns a list of supported backends"
backends() = _backends backends() = _backends
"Returns the name of the current backend"
backend_name() = CURRENT_BACKEND.sym backend_name() = CURRENT_BACKEND.sym
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym") _backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")

View File

@ -24,7 +24,8 @@ const _glvisualize_attr = merge_with_base_supported([
:window_title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation, :guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :colorbar,
:marker_z, :marker_z,
:line_z, :line_z,
:levels, :levels,
@ -38,7 +39,8 @@ const _glvisualize_attr = merge_with_base_supported([
:clims, :clims,
:inset_subplots, :inset_subplots,
:dpi, :dpi,
:hover :hover,
:framestyle,
]) ])
const _glvisualize_seriestype = [ const _glvisualize_seriestype = [
:path, :shape, :path, :shape,
@ -676,17 +678,29 @@ function text_model(font, pivot)
end end
end end
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area) function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
xticks, yticks, spine_segs, grid_segs = Plots.axis_drawing_info(sp) xticks, yticks, xspine_segs, yspine_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
xaxis = sp[:xaxis]; yaxis = sp[:yaxis] xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
c = Colors.color(Plots.gl_color(sp[:foreground_color_grid])) xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
ygc = Colors.color(Plots.gl_color(yaxis[:foreground_color_grid]))
axis_vis = [] axis_vis = []
if sp[:grid] if xaxis[:grid]
grid = draw_grid_lines(sp, grid_segs, 1f0, :dot, model, RGBA(c, 0.3f0)) grid = draw_grid_lines(sp, xgrid_segs, xaxis[:gridlinewidth], xaxis[:gridstyle], model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, grid) push!(axis_vis, grid)
end end
if alpha(xaxis[:foreground_color_border]) > 0 if yaxis[:grid]
spine = draw_grid_lines(sp, spine_segs, 1f0, :solid, model, RGBA(c, 1.0f0)) grid = draw_grid_lines(sp, ygrid_segs, yaxis[:gridlinewidth], yaxis[:gridstyle], model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, grid)
end
xac = Colors.color(Plots.gl_color(xaxis[:foreground_color_axis]))
yac = Colors.color(Plots.gl_color(yaxis[:foreground_color_axis]))
if alpha(xaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, xspine_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
push!(axis_vis, spine)
end
if alpha(yaxis[:foreground_color_axis]) > 0
spine = draw_grid_lines(sp, yspine_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
push!(axis_vis, spine) push!(axis_vis, spine)
end end
fcolor = Plots.gl_color(xaxis[:foreground_color_axis]) fcolor = Plots.gl_color(xaxis[:foreground_color_axis])
@ -694,7 +708,7 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
xlim = Plots.axis_limits(xaxis) xlim = Plots.axis_limits(xaxis)
ylim = Plots.axis_limits(yaxis) ylim = Plots.axis_limits(yaxis)
if !(xaxis[:ticks] in (nothing, false, :none)) if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none)
ticklabels = map(model) do m ticklabels = map(model) do m
mirror = xaxis[:mirror] mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(xaxis, xticks, true, ylim, m) t, positions, offsets = draw_ticks(xaxis, xticks, true, ylim, m)
@ -714,6 +728,15 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args)) push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end end
xbc = Colors.color(Plots.gl_color(xaxis[:foreground_color_border]))
ybc = Colors.color(Plots.gl_color(yaxis[:foreground_color_border]))
intensity = sp[:framestyle] == :semi ? 0.5f0 : 1.0f0
if sp[:framestyle] in (:box, :semi)
xborder = draw_grid_lines(sp, xborder_segs, intensity, :solid, model, RGBA(xbc, intensity))
yborder = draw_grid_lines(sp, yborder_segs, intensity, :solid, model, RGBA(ybc, intensity))
push!(axis_vis, xborder, yborder)
end
area_w = GeometryTypes.widths(area) area_w = GeometryTypes.widths(area)
if sp[:title] != "" if sp[:title] != ""
tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title]) tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title])

View File

@ -20,7 +20,8 @@ const _gr_attr = merge_with_base_supported([
:title, :window_title, :title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :guide, :lims, :ticks, :scale, :flip,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :levels, :marker_z, :levels,
:ribbon, :quiver, :ribbon, :quiver,
:orientation, :orientation,
@ -31,6 +32,7 @@ const _gr_attr = merge_with_base_supported([
:inset_subplots, :inset_subplots,
:bar_width, :bar_width,
:arrow, :arrow,
:framestyle,
]) ])
const _gr_seriestype = [ const _gr_seriestype = [
:path, :scatter, :path, :scatter,
@ -325,7 +327,10 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
cfuncind(ci) cfuncind(ci)
GR.settransparency(_gr_gradient_alpha[ci-999]) GR.settransparency(_gr_gradient_alpha[ci-999])
end end
gr_draw_marker(x[i], y[i], msi, shape) # don't draw filled area if marker shape is 1D
if !(shape in (:hline, :vline, :+, :x))
gr_draw_marker(x[i], y[i], msi, shape)
end
end end
end end
end end
@ -336,6 +341,7 @@ function gr_draw_markers(series::Series, x, y)
GR.setfillintstyle(GR.INTSTYLE_SOLID) GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_draw_markers(series, x, y, series[:markersize], mz) gr_draw_markers(series, x, y, series[:markersize], mz)
if mz != nothing if mz != nothing
GR.setscale(0)
gr_colorbar(series[:subplot]) gr_colorbar(series[:subplot])
end end
end end
@ -537,40 +543,91 @@ function gr_display(plt::Plot)
end end
function gr_set_xticks_font(sp)
flip = sp[:yaxis][:flip]
mirror = sp[:xaxis][:mirror]
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = (mirror ? :bottom : :top),
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation])
return flip, mirror
end
function gr_set_yticks_font(sp)
flip = sp[:xaxis][:flip]
mirror = sp[:yaxis][:mirror]
gr_set_font(sp[:yaxis][:tickfont],
halign = (mirror ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
color = sp[:yaxis][:foreground_color_axis],
rotation = sp[:yaxis][:rotation])
return flip, mirror
end
function gr_get_ticks_size(ticks, i)
GR.savestate()
GR.selntran(0)
l = 0.0
for (cv, dv) in zip(ticks...)
tb = gr_inqtext(0, 0, string(dv))[i]
tb_min, tb_max = extrema(tb)
l = max(l, tb_max - tb_min)
end
GR.restorestate()
return l
end
function _update_min_padding!(sp::Subplot{GRBackend}) function _update_min_padding!(sp::Subplot{GRBackend})
leftpad = 10mm if !haskey(ENV, "GKSwstype")
toppad = 2mm if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
rightpad = 2mm ENV["GKSwstype"] = "svg"
bottompad = 6mm end
end
# Add margin given by the user
leftpad = 2mm + sp[:left_margin]
toppad = 2mm + sp[:top_margin]
rightpad = 4mm + sp[:right_margin]
bottompad = 2mm + sp[:bottom_margin]
# Add margin for title
if sp[:title] != "" if sp[:title] != ""
toppad += 5mm toppad += 5mm
end end
if sp[:xaxis][:guide] != "" # Add margin for x and y ticks
xticks = axis_drawing_info(sp)[1] xticks, yticks = axis_drawing_info(sp)[1:2]
if !(xticks in (nothing, false)) if !(xticks in (nothing, false))
gr_set_font(sp[:xaxis][:tickfont], flip, mirror = gr_set_xticks_font(sp)
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2], l = gr_get_ticks_size(xticks, 2)
valign = :top, if mirror
color = sp[:xaxis][:foreground_color_axis], toppad += 1mm + gr_plot_size[2] * l * px
rotation = sp[:xaxis][:rotation])
h = 0
for (cv, dv) in zip(xticks...)
tbx, tby = gr_inqtext(0, 0, string(dv))
h = max(h, tby[2] - tby[1])
end
bottompad += 1mm + gr_plot_size[2] * h * px
else else
bottompad += 4mm bottompad += 1mm + gr_plot_size[2] * l * px
end end
end end
if !(yticks in (nothing, false))
flip, mirror = gr_set_yticks_font(sp)
l = gr_get_ticks_size(yticks, 1)
if mirror
rightpad += 1mm + gr_plot_size[1] * l * px
else
leftpad += 1mm + gr_plot_size[1] * l * px
end
end
# Add margin for x label
if sp[:xaxis][:guide] != ""
bottompad += 4mm
end
# Add margin for y label
if sp[:yaxis][:guide] != "" if sp[:yaxis][:guide] != ""
leftpad += 4mm leftpad += 4mm
end end
sp.minpad = (leftpad, toppad, rightpad, bottompad) sp.minpad = (leftpad, toppad, rightpad, bottompad)
end end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
_update_min_padding!(sp)
# the viewports for this subplot # the viewports for this subplot
viewport_subplot = gr_viewport_from_bbox(sp, bbox(sp), w, h, viewport_canvas) viewport_subplot = gr_viewport_from_bbox(sp, bbox(sp), w, h, viewport_canvas)
viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas) viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas)
@ -606,7 +663,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# TODO: can these be generic flags? # TODO: can these be generic flags?
outside_ticks = false outside_ticks = false
cmap = false cmap = false
draw_axes = true draw_axes = sp[:framestyle] != :none
# axes_2d = true # axes_2d = true
for series in series_list(sp) for series in series_list(sp)
st = series[:seriestype] st = series[:seriestype]
@ -691,10 +748,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1]) ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1])
# GR.setlinetype(GR.LINETYPE_DOTTED) # GR.setlinetype(GR.LINETYPE_DOTTED)
if sp[:grid] xaxis[:grid] && GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0)
GR.grid3d(xtick, 0, ztick, xmin, ymax, zmin, 2, 0, 2) yaxis[:grid] && GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0) zaxis[:grid] && GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2)
end
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize) GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize) GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
@ -709,34 +765,37 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setwindow(xmin, xmax, ymin, ymax) GR.setwindow(xmin, xmax, ymin, ymax)
end end
xticks, yticks, spine_segs, grid_segs = axis_drawing_info(sp) xticks, yticks, xspine_segs, yspine_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
# @show xticks yticks #spine_segs grid_segs # @show xticks yticks #spine_segs grid_segs
# draw the grid lines # draw the grid lines
if sp[:grid] if xaxis[:grid]
# gr_set_linecolor(sp[:foreground_color_grid]) # gr_set_linecolor(sp[:foreground_color_grid])
# GR.grid(xtick, ytick, 0, 0, majorx, majory) # GR.grid(xtick, ytick, 0, 0, majorx, majory)
gr_set_line(1, :dot, sp[:foreground_color_grid]) gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
GR.settransparency(0.5) GR.settransparency(xaxis[:gridalpha])
gr_polyline(coords(grid_segs)...) gr_polyline(coords(xgrid_segs)...)
end
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
GR.settransparency(yaxis[:gridalpha])
gr_polyline(coords(ygrid_segs)...)
end end
GR.settransparency(1.0) GR.settransparency(1.0)
# spine (border) and tick marks # axis lines
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis]) gr_set_line(1, :solid, xaxis[:foreground_color_axis])
GR.setclip(0) GR.setclip(0)
gr_polyline(coords(spine_segs)...) gr_polyline(coords(xspine_segs)...)
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(yspine_segs)...)
GR.setclip(1) GR.setclip(1)
if !(xticks in (nothing, false)) # tick marks
if !(xticks in (:none, nothing, false))
# x labels # x labels
flip = sp[:yaxis][:flip] flip, mirror = gr_set_xticks_font(sp)
mirror = sp[:xaxis][:mirror]
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = (mirror ? :bottom : :top),
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation])
for (cv, dv) in zip(xticks...) for (cv, dv) in zip(xticks...)
# use xor ($) to get the right y coords # use xor ($) to get the right y coords
xi, yi = GR.wctondc(cv, xor(flip, mirror) ? ymax : ymin) xi, yi = GR.wctondc(cv, xor(flip, mirror) ? ymax : ymin)
@ -745,15 +804,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end end
end end
if !(yticks in (nothing, false)) if !(yticks in (:none, nothing, false))
# y labels # y labels
flip = sp[:xaxis][:flip] flip, mirror = gr_set_yticks_font(sp)
mirror = sp[:yaxis][:mirror]
gr_set_font(sp[:yaxis][:tickfont],
halign = (mirror ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
color = sp[:yaxis][:foreground_color_axis],
rotation = sp[:yaxis][:rotation])
for (cv, dv) in zip(yticks...) for (cv, dv) in zip(yticks...)
# use xor ($) to get the right y coords # use xor ($) to get the right y coords
xi, yi = GR.wctondc(xor(flip, mirror) ? xmax : xmin, cv) xi, yi = GR.wctondc(xor(flip, mirror) ? xmax : xmin, cv)
@ -761,6 +814,17 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv)) gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv))
end end
end end
# border
intensity = sp[:framestyle] == :semi ? 0.5 : 1.0
if sp[:framestyle] in (:box, :semi)
gr_set_line(intensity, :solid, xaxis[:foreground_color_border])
GR.settransparency(intensity)
gr_polyline(coords(xborder_segs)...)
gr_set_line(intensity, :solid, yaxis[:foreground_color_border])
GR.settransparency(intensity)
gr_polyline(coords(yborder_segs)...)
end
end end
# end # end
@ -863,7 +927,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if series[:marker_z] != nothing if series[:marker_z] != nothing
zmin, zmax = extrema(series[:marker_z]) zmin, zmax = extrema(series[:marker_z])
GR.setspace(zmin, zmax, 0, 90) GR.setspace(zmin, zmax, 0, 90)
GR.setscale(0)
end end
gr_draw_markers(series, x, y) gr_draw_markers(series, x, y)
end end
@ -1088,7 +1151,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
st = series[:seriestype] st = series[:seriestype]
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha]) gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
if st == :shape || series[:fillrange] != nothing if (st == :shape || series[:fillrange] != nothing) && series[:ribbon] == nothing
gr_set_fill(series[:fillcolor]) #, series[:fillalpha]) gr_set_fill(series[:fillcolor]) #, series[:fillalpha])
l, r = xpos-0.07, xpos-0.01 l, r = xpos-0.07, xpos-0.01
b, t = ypos-0.4dy, ypos+0.4dy b, t = ypos-0.4dy, ypos+0.4dy

View File

@ -18,7 +18,8 @@ Add in functionality to Plots.jl:
const _inspectdr_attr = merge_with_base_supported([ const _inspectdr_attr = merge_with_base_supported([
:annotations, :annotations,
:background_color_legend, :background_color_inside, :background_color_outside, :background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title, # :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text, :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label, :label,
:linecolor, :linestyle, :linewidth, :linealpha, :linecolor, :linestyle, :linewidth, :linealpha,
@ -334,15 +335,18 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend}) function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
const gridon = InspectDR.GridRect(vmajor=true, hmajor=true)
const gridoff = InspectDR.GridRect()
const plot = sp.o const plot = sp.o
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
#No independent control of grid???
strip.grid = sp[:grid]? gridon: gridoff
xaxis = sp[:xaxis]; yaxis = sp[:yaxis] xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
ygrid_show = yaxis[:grid]
strip.grid = InspectDR.GridRect(
vmajor=xgrid_show, # vminor=xgrid_show,
hmajor=ygrid_show, # hminor=ygrid_show,
)
plot.xscale = _inspectdr_getscale(xaxis[:scale], false) plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true) strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(xaxis) xmin, xmax = axis_limits(xaxis)

View File

@ -98,7 +98,7 @@ const _pgf_series_extrastyle = KW(
:xsticks => "xcomb", :xsticks => "xcomb",
) )
# PGFPlots uses the anchors to define orientations for example to align left # PGFPlots uses the anchors to define orientations for example to align left
# one needs to use the right edge as anchor # one needs to use the right edge as anchor
const _pgf_annotation_halign = KW( const _pgf_annotation_halign = KW(
:center => "", :center => "",
@ -121,7 +121,7 @@ function pgf_color(grad::ColorGradient)
end end
# Generates a colormap for pgfplots based on a ColorGradient # Generates a colormap for pgfplots based on a ColorGradient
function pgf_colormap(grad::ColorGradient) function pgf_colormap(grad::ColorGradient)
join(map(grad.colors) do c join(map(grad.colors) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
end,", ") end,", ")
@ -266,6 +266,11 @@ function pgf_axis(sp::Subplot, letter)
push!(style, "$(letter)majorticks=false") push!(style, "$(letter)majorticks=false")
end end
# grid on or off
if axis[:grid]
push!(style, "$(letter)majorgrids = true")
end
# limits # limits
# TODO: support zlims # TODO: support zlims
if letter != :z if letter != :z
@ -324,7 +329,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:title] = "$(sp[:title])" kw[:title] = "$(sp[:title])"
end end
sp[:grid] && push!(style, "grid = major")
if sp[:aspect_ratio] in (1, :equal) if sp[:aspect_ratio] in (1, :equal)
kw[:axisEqual] = "true" kw[:axisEqual] = "true"
end end
@ -360,7 +364,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:colorbar] = "true" kw[:colorbar] = "true"
end end
# goto is needed to break out of col and series for # goto is needed to break out of col and series for
@goto colorbar_end @goto colorbar_end
end end
end end
end end

View File

@ -5,7 +5,7 @@ const _plotly_attr = merge_with_base_supported([
:annotations, :annotations,
:background_color_legend, :background_color_inside, :background_color_outside, :background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide, :foreground_color_legend, :foreground_color_guide,
# :foreground_color_grid, :foreground_color_axis, :foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border, :foreground_color_text, :foreground_color_border,
:foreground_color_title, :foreground_color_title,
:label, :label,
@ -19,7 +19,8 @@ const _plotly_attr = merge_with_base_supported([
:window_title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation, :guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar, :colorbar_title, :grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :levels, :marker_z, :fill_z, :levels,
:ribbon, :quiver, :ribbon, :quiver,
:orientation, :orientation,
@ -213,7 +214,9 @@ function plotly_axis(axis::Axis, sp::Subplot)
letter = axis[:letter] letter = axis[:letter]
ax = KW( ax = KW(
:title => axis[:guide], :title => axis[:guide],
:showgrid => sp[:grid], :showgrid => axis[:grid],
:gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
:gridwidth => axis[:gridlinewidth],
:zeroline => false, :zeroline => false,
:ticks => "inside", :ticks => "inside",
) )
@ -229,8 +232,8 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide]) ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
ax[:type] = plotly_scale(axis[:scale]) ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text]) ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
ax[:tickcolor] = rgba_string(axis[:foreground_color_border]) ax[:tickcolor] = rgba_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_border]) ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# lims # lims
lims = axis[:lims] lims = axis[:lims]
@ -435,7 +438,8 @@ function plotly_series(plt::Plot, series::Series)
isscatter = st in (:scatter, :scatter3d, :scattergl) isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d) hasline = st in (:path, :path3d)
hasfillrange = st in (:path, :scatter, :scattergl) && isa(series[:fillrange], AbstractVector) hasfillrange = st in (:path, :scatter, :scattergl) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
# for surface types, set the data # for surface types, set the data
if st in (:heatmap, :contour, :surface, :wireframe) if st in (:heatmap, :contour, :surface, :wireframe)
@ -459,7 +463,7 @@ function plotly_series(plt::Plot, series::Series)
else else
hasline ? "lines" : "none" hasline ? "lines" : "none"
end end
if series[:fillrange] == true || series[:fillrange] == 0 if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
d_out[:fill] = "tozeroy" d_out[:fill] = "tozeroy"
d_out[:fillcolor] = rgba_string(series[:fillcolor]) d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif isa(series[:fillrange], AbstractVector) elseif isa(series[:fillrange], AbstractVector)
@ -584,11 +588,21 @@ function plotly_series(plt::Plot, series::Series)
if hasfillrange if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original # if hasfillrange is true, return two dictionaries (one for original
# series, one for series being filled to) instead of one # series, one for series being filled to) instead of one
d_out_fillrange = copy(d_out) d_out_fillrange = deepcopy(d_out)
d_out_fillrange[:y] = series[:fillrange]
d_out_fillrange[:showlegend] = false d_out_fillrange[:showlegend] = false
delete!(d_out_fillrange, :fill) if isa(series[:fillrange], AbstractVector)
delete!(d_out_fillrange, :fillcolor) d_out_fillrange[:y] = series[:fillrange]
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
else
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
# is the series that will do the filling
d_out_fillrange[:x], d_out_fillrange[:y] =
concatenate_fillrange(series[:x], series[:fillrange])
d_out_fillrange[:line][:width] = 0
delete!(d_out, :fill)
delete!(d_out, :fillcolor)
end
return [d_out_fillrange, d_out] return [d_out_fillrange, d_out]
else else

View File

@ -17,7 +17,8 @@ const _pyplot_attr = merge_with_base_supported([
:window_title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation, :guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z, :marker_z, :line_z, :fill_z,
:levels, :levels,
:ribbon, :quiver, :arrow, :ribbon, :quiver, :arrow,
@ -32,6 +33,7 @@ const _pyplot_attr = merge_with_base_supported([
:dpi, :dpi,
:colorbar_title, :colorbar_title,
:stride, :stride,
:framestyle,
]) ])
const _pyplot_seriestype = [ const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape, :path, :steppre, :steppost, :shape,
@ -1053,7 +1055,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end end
py_set_scale(ax, axis) py_set_scale(ax, axis)
py_set_lims(ax, axis) py_set_lims(ax, axis)
py_set_ticks(ax, get_ticks(axis), letter) ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
py_set_ticks(ax, ticks, letter)
ax[Symbol("set_", letter, "label")](axis[:guide]) ax[Symbol("set_", letter, "label")](axis[:guide])
if get(axis.d, :flip, false) if get(axis.d, :flip, false)
ax[Symbol("invert_", letter, "axis")]() ax[Symbol("invert_", letter, "axis")]()
@ -1065,9 +1068,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
lab[:set_family](axis[:tickfont].family) lab[:set_family](axis[:tickfont].family)
lab[:set_rotation](axis[:rotation]) lab[:set_rotation](axis[:rotation])
end end
if sp[:grid] if axis[:grid] && !(ticks in (:none, nothing, false))
fgcolor = py_color(sp[:foreground_color_grid]) fgcolor = py_color(axis[:foreground_color_grid])
pyaxis[:grid](true, color = fgcolor, linestyle = ":") pyaxis[:grid](true,
color = fgcolor,
linestyle = py_linestyle(:line, axis[:gridstyle]),
linewidth = axis[:gridlinewidth],
alpha = axis[:gridalpha])
ax[:set_axisbelow](true) ax[:set_axisbelow](true)
end end
py_set_axis_colors(ax, axis) py_set_axis_colors(ax, axis)
@ -1084,6 +1091,24 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
# this sets the bg color inside the grid # this sets the bg color inside the grid
ax[set_facecolor_sym](py_color(sp[:background_color_inside])) ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
# framestyle
if !ispolar(sp) && !is3d(sp)
if sp[:framestyle] == :semi
intensity = 0.5
ax[:spines]["right"][:set_alpha](intensity)
ax[:spines]["top"][:set_alpha](intensity)
ax[:spines]["right"][:set_linewidth](intensity)
ax[:spines]["top"][:set_linewidth](intensity)
elseif sp[:framestyle] == :axes
ax[:spines]["right"][:set_visible](false)
ax[:spines]["top"][:set_visible](false)
elseif sp[:framestyle] in (:grid, :none)
for (loc, spine) in ax[:spines]
spine[:set_visible](false)
end
end
end
end end
py_drawfig(fig) py_drawfig(fig)
end end

View File

@ -22,6 +22,13 @@ immutable Shape
# end # end
# end # end
end end
"""
Shape(x, y)
Shape(vertices)
Construct a polygon to be plotted
"""
Shape(verts::AVec) = Shape(unzip(verts)...) Shape(verts::AVec) = Shape(unzip(verts)...)
Shape(s::Shape) = deepcopy(s) Shape(s::Shape) = deepcopy(s)
@ -32,6 +39,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
#deprecated #deprecated
@deprecate shape_coords coords @deprecate shape_coords coords
"return the vertex points from a Shape or Segments object"
function coords(shape::Shape) function coords(shape::Shape)
shape.x, shape.y shape.x, shape.y
end end
@ -156,6 +164,7 @@ Shape(k::Symbol) = deepcopy(_shapes[k])
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon # uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
"return the centroid of a Shape"
function center(shape::Shape) function center(shape::Shape)
x, y = coords(shape) x, y = coords(shape)
n = length(x) n = length(x)
@ -189,6 +198,7 @@ function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
scale!(shapecopy, x, y, c) scale!(shapecopy, x, y, c)
end end
"translate a Shape in space"
function translate!(shape::Shape, x::Real, y::Real = x) function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape) sx, sy = coords(shape)
for i=1:length(sx) for i=1:length(sx)
@ -227,6 +237,7 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
shape shape
end end
"rotate an object in space"
function rotate(shape::Shape, Θ::Real, c = center(shape)) function rotate(shape::Shape, Θ::Real, c = center(shape))
shapecopy = deepcopy(shape) shapecopy = deepcopy(shape)
rotate!(shapecopy, Θ, c) rotate!(shapecopy, Θ, c)
@ -331,6 +342,11 @@ immutable PlotText
end end
PlotText(str) = PlotText(string(str), font()) PlotText(str) = PlotText(string(str), font())
"""
text(string, args...)
Create a PlotText object wrapping a string with font info, for plot annotations
"""
text(t::PlotText) = t text(t::PlotText) = t
text(str::AbstractString, f::Font) = PlotText(str, f) text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...) function text(str, args...)
@ -350,6 +366,11 @@ immutable Stroke
style style
end end
"""
stroke(args...; alpha = nothing)
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing) function stroke(args...; alpha = nothing)
width = 1 width = 1
color = :black color = :black
@ -597,6 +618,12 @@ immutable Arrow
headwidth::Float64 headwidth::Float64
end end
"""
arrow(args...)
Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
`side` (`:head`, `:tail` or `:both`), `headlength` and `headwidth`
"""
function arrow(args...) function arrow(args...)
style = :simple style = :simple
side = :head side = :head
@ -652,7 +679,7 @@ immutable Formatted{T}
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"create a BezierCurve for plotting"
type BezierCurve{T <: FixedSizeArrays.Vec} type BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T} control_points::Vector{T}
end end

View File

@ -155,7 +155,7 @@ PlotExample("Subplots",
""", """,
[:(begin [:(begin
l = @layout([a{0.1h}; b [c;d e]]) 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=false) plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=:none)
end)] end)]
), ),
@ -290,7 +290,7 @@ PlotExample("Layouts, margins, label rotation, title location",
[:(begin [:(begin
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"], plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
title_location=:left, left_margin=[20mm 0mm], title_location=:left, left_margin=[20mm 0mm],
bottom_margin=50px, xrotation=60) bottom_margin=10px, xrotation=60)
end)] end)]
), ),
@ -321,7 +321,7 @@ PlotExample("Animation with subplots",
), ),
PlotExample("Spy", 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`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`", "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`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`.",
[:(begin [:(begin
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10)) a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10)) b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
@ -329,6 +329,26 @@ PlotExample("Spy",
end)] 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
histogram(fill(randn(1000), 5), framestyle = [:box :semi :axes :grid :none],
title = [":box" ":semi" ":axes" ":grid" ":none"], color = RowVector(1:5), layout = 5, label = "")
end)]
),
] ]
# --------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------
@ -348,6 +368,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
end end
# generate all plots and create a dict mapping idx --> plt # 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, function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing) skip = [], only = nothing)
Plots._debugMode.on = debug Plots._debugMode.on = debug

View File

@ -133,7 +133,12 @@ make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h make_measure_vert(n::Number) = n * h
make_measure_vert(m::Measure) = m make_measure_vert(m::Measure) = m
"""
bbox(x, y, w, h [,originargs...])
bbox(layout)
Create a bounding box for plotting
"""
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...) function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
oargs = vcat(oarg1, originargs...) oargs = vcat(oarg1, originargs...)
orighor = :left orighor = :left
@ -253,6 +258,13 @@ type GridLayout <: AbstractLayout
attr::KW attr::KW
end end
"""
grid(args...; kw...)
Create a grid layout for subplots. `args` specify the dimensions, e.g.
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two
columns of different width.
"""
grid(args...; kw...) = GridLayout(args...; kw...) grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout(dims...; function GridLayout(dims...;

View File

@ -97,6 +97,13 @@ function addExtension(fn::AbstractString, ext::AbstractString)
end end
end end
"""
savefig([plot,] filename)
Save a Plot (the current plot if `plot` is not passed) to file. The file
type is inferred from the file extension. All backends support png and pdf
file types, some also support svg, ps, eps, html and tex.
"""
function savefig(plt::Plot, fn::AbstractString) function savefig(plt::Plot, fn::AbstractString)
# get the extension # get the extension
@ -119,7 +126,11 @@ savefig(fn::AbstractString) = savefig(current(), fn)
# --------------------------------------------------------- # ---------------------------------------------------------
"""
gui([plot])
Display a plot using the backends' gui window
"""
gui(plt::Plot = current()) = display(PlotsDisplay(), plt) gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
# IJulia only... inline display # IJulia only... inline display
@ -198,6 +209,7 @@ for mime in keys(_mimeformats)
end end
end end
"Close all open gui windows of the current backend"
closeall() = closeall(backend()) closeall() = closeall(backend())
@ -266,6 +278,7 @@ using Requires
show(io, MIME("text/html"), plt) show(io, MIME("text/html"), plt)
end end
ENV["MPLBACKEND"] = "Agg"
set_ijulia_output("text/html") set_ijulia_output("text/html")
end end
end end

View File

@ -60,29 +60,26 @@ function _process_userrecipes(plt::Plot, d::KW, args)
args = _preprocess_args(d, args, still_to_process) args = _preprocess_args(d, args, still_to_process)
# for plotting recipes, swap out the args and update the parameter dictionary # for plotting recipes, swap out the args and update the parameter dictionary
# we are keeping a queue of series that still need to be processed. # we are keeping a stack of series that still need to be processed.
# each pass through the loop, we pop one off and apply the recipe. # each pass through the loop, we pop one off and apply the recipe.
# the recipe will return a list a Series objects... the ones that are # the recipe will return a list a Series objects... the ones that are
# finished (no more args) get added to the kw_list, and the rest go into the queue # finished (no more args) get added to the kw_list, the ones that are not
# for processing. # are placed on top of the stack and are then processed further.
kw_list = KW[] kw_list = KW[]
while !isempty(still_to_process) while !isempty(still_to_process)
# grab the first in line to be processed and pass it through apply_recipe # grab the first in line to be processed and either add it to the kw_list or
# to generate a list of RecipeData objects (data + attributes) # pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
# for further processing.
next_series = shift!(still_to_process) next_series = shift!(still_to_process)
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...) # recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
for recipedata in rd_list if !(typeof(next_series) <: RecipeData)
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
if !(typeof(recipedata) <: RecipeData) end
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata") if isempty(next_series.args)
end _process_userrecipe(plt, kw_list, next_series)
else
if isempty(recipedata.args) rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
_process_userrecipe(plt, kw_list, recipedata) prepend!(still_to_process,rd_list)
else
# args are non-empty, so there's still processing to do... add it back to the queue
push!(still_to_process, recipedata)
end
end end
end end
@ -213,7 +210,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# TODO: init subplots here # TODO: init subplots here
_update_plot_args(plt, d) _update_plot_args(plt, d)
if !plt.init if !plt.init
plt.o = _create_backend_figure(plt) plt.o = Base.invokelatest(_create_backend_figure, plt)
# create the layout and subplots from the inputs # create the layout and subplots from the inputs
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr) plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)

View File

@ -6,6 +6,10 @@ const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
isplotnull() = isnull(CURRENT_PLOT.nullableplot) isplotnull() = isnull(CURRENT_PLOT.nullableplot)
"""
current()
Returns the Plot object for the current plot
"""
function current() function current()
if isplotnull() if isplotnull()
error("No current plot/subplot") error("No current plot/subplot")

View File

@ -14,6 +14,12 @@ function lookup_aliases(attrtype, attribute)
error("There is no attribute named $attribute in $attrtype") error("There is no attribute named $attribute in $attrtype")
end end
"""
plotattr([attr])
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
The information is the same as that given on https://juliaplots.github.io/attributes/.
"""
function plotattr() function plotattr()
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())") println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
end end

View File

@ -510,8 +510,10 @@ function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode
v = vs[dim] v = vs[dim]
if mode == :auto if mode == :auto
30 mode = :fd
elseif mode == :sqrt # Square-root choice end
if mode == :sqrt # Square-root choice
_cl(sqrt(n)) _cl(sqrt(n))
elseif mode == :sturges # Sturges' formula elseif mode == :sturges # Sturges' formula
_cl(log2(n)) + 1 _cl(log2(n)) + 1
@ -550,7 +552,7 @@ end
@recipe function f(::Type{Val{:histogram}}, x, y, z) @recipe function f(::Type{Val{:histogram}}, x, y, z)
seriestype := :barhist seriestype := length(y) > 1e6 ? :stephist : :barhist
() ()
end end
@deps histogram barhist @deps histogram barhist
@ -847,6 +849,7 @@ end
# TODO: move OHLC to PlotRecipes finance.jl # TODO: move OHLC to PlotRecipes finance.jl
"Represent Open High Low Close data (used in finance)"
type OHLC{T<:Real} type OHLC{T<:Real}
open::T open::T
high::T high::T

View File

@ -509,12 +509,25 @@ end
# nothing # nothing
# end # end
splittable_kw(key, val, lengthGroup) = false
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val)-1)...]
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
# split the group into 1 series per group, and set the label and idxfilter for each # split the group into 1 series per group, and set the label and idxfilter for each
@recipe function f(groupby::GroupBy, args...) @recipe function f(groupby::GroupBy, args...)
lengthGroup = maximum(union(groupby.groupIds...))
for (i,glab) in enumerate(groupby.groupLabels) for (i,glab) in enumerate(groupby.groupLabels)
@series begin @series begin
label --> string(glab) label --> string(glab)
idxfilter --> groupby.groupIds[i] idxfilter --> groupby.groupIds[i]
for (key,val) in d
if splittable_kw(key, val, lengthGroup)
:($key) := split_kw(key, val, groupby.groupIds[i])
end
end
args args
end end
end end

View File

@ -13,6 +13,11 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
) )
end end
"""
plotarea(subplot)
Return the bounding box of a subplot
"""
plotarea(sp::Subplot) = sp.plotarea plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox) plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)

View File

@ -1,4 +1,8 @@
"""
theme(s::Symbol)
Specify the colour theme for plots.
"""
function theme(s::Symbol; kw...) function theme(s::Symbol; kw...)
# reset? # reset?
if s == :none || s == :default if s == :none || s == :default

View File

@ -137,7 +137,7 @@ function imageHack(d::KW)
end end
# --------------------------------------------------------------- # ---------------------------------------------------------------
"Build line segments for plotting"
type Segments{T} type Segments{T}
pts::Vector{T} pts::Vector{T}
end end
@ -185,6 +185,7 @@ type SegmentsIterator
args::Tuple args::Tuple
n::Int n::Int
end end
function iter_segments(args...) function iter_segments(args...)
tup = Plots.wraptuple(args) tup = Plots.wraptuple(args)
n = maximum(map(length, tup)) n = maximum(map(length, tup))
@ -495,14 +496,42 @@ function make_fillrange_from_ribbon(kw::KW)
rib1, rib2 = -first(rib), last(rib) rib1, rib2 = -first(rib), last(rib)
# kw[:ribbon] = nothing # kw[:ribbon] = nothing
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2) kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
(get(kw, :fillalpha, nothing) == nothing) && (kw[:fillalpha] = 0.5)
end
#turn tuple of fillranges to one path
function concatenate_fillrange(x,y::Tuple)
rib1, rib2 = first(y), last(y)
yline = vcat(rib1,(rib2)[end:-1:1])
xline = vcat(x,x[end:-1:1])
return xline, yline
end end
function get_sp_lims(sp::Subplot, letter::Symbol) function get_sp_lims(sp::Subplot, letter::Symbol)
axis_limits(sp[Symbol(letter, :axis)]) axis_limits(sp[Symbol(letter, :axis)])
end end
"""
xlims([plt])
Returns the x axis limits of the current plot or subplot
"""
xlims(sp::Subplot) = get_sp_lims(sp, :x) xlims(sp::Subplot) = get_sp_lims(sp, :x)
"""
ylims([plt])
Returns the y axis limits of the current plot or subplot
"""
ylims(sp::Subplot) = get_sp_lims(sp, :y) ylims(sp::Subplot) = get_sp_lims(sp, :y)
"""
zlims([plt])
Returns the z axis limits of the current plot or subplot
"""
zlims(sp::Subplot) = get_sp_lims(sp, :z) zlims(sp::Subplot) = get_sp_lims(sp, :z)
xlims(plt::Plot, sp_idx::Int = 1) = xlims(plt[sp_idx]) xlims(plt::Plot, sp_idx::Int = 1) = xlims(plt[sp_idx])
ylims(plt::Plot, sp_idx::Int = 1) = ylims(plt[sp_idx]) ylims(plt::Plot, sp_idx::Int = 1) = ylims(plt[sp_idx])
zlims(plt::Plot, sp_idx::Int = 1) = zlims(plt[sp_idx]) zlims(plt::Plot, sp_idx::Int = 1) = zlims(plt[sp_idx])
@ -536,7 +565,7 @@ allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
""" """
Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example: Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example:
``` ```
with(:gadfly, size=(400,400), type=:histogram) do with(:gr, size=(400,400), type=:histogram) do
plot(rand(10)) plot(rand(10))
plot(rand(10)) plot(rand(10))
end end

View File

@ -23,7 +23,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that # TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition) # is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.12.1" const _current_plots_version = v"0.12.3"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2) function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
@ -42,7 +42,8 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
fn = "ref$idx.png" fn = "ref$idx.png"
# firgure out version info # firgure out version info
versions = sort(VersionNumber.(readdir(refdir)), rev = true) vns = filter(x->x[1] != '.', readdir(refdir))
versions = sort(VersionNumber.(vns), rev = true)
versions = filter(v -> v <= _current_plots_version, versions) versions = filter(v -> v <= _current_plots_version, versions)
# @show refdir fn versions # @show refdir fn versions

View File

@ -8,6 +8,7 @@ default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2 img_eps = isinteractive() ? 1e-2 : 10e-2
@testset "GR" begin @testset "GR" begin
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend() @test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend() @test backend() == Plots.GRBackend()