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)
## 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 markers not showing up in seriesrecipes using :scatter
- don't use pywrap in the pyplot backend
- improve the bottom margin for the gr backend
## 0.12.1
#### 0.12.1
- fix deprecation warnings
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays

View File

@ -1,6 +1,7 @@
# Plots
[![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)
<!-- [![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) -->

View File

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

View File

@ -1,7 +1,13 @@
environment:
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/x64/0.5/julia-0.5-latest-win64.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.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/x64/julia-latest-win64.exe"

View File

@ -8,7 +8,7 @@ import StaticArrays
using StaticArrays.FixedSizeArrays
@reexport using RecipesBase
import RecipesBase: plot, animate
import RecipesBase: plot, plot!, animate
using Base.Meta
@reexport using PlotUtils
@reexport using PlotThemes
@ -52,6 +52,8 @@ export
yflip!,
xaxis!,
yaxis!,
xgrid!,
ygrid!,
xlims,
ylims,
@ -186,33 +188,65 @@ include("output.jl")
@shorthands quiver
@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)
"Plot with 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...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
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...)
"Set ylims for an existing plot"
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...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), 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...)
"Set yticks for an existing plot"
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(
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!{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...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
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}
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...)
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
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!{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...)

View File

@ -1,4 +1,4 @@
"Represents an animation object"
immutable Animation
dir::String
frames::Vector{String}
@ -9,6 +9,11 @@ function Animation()
Animation(tmpdir, String[])
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())
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
@ -81,7 +86,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString;
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
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...)""")
# low quality

View File

@ -21,7 +21,7 @@ const _arg_desc = KW(
: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`.",
: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?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
: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.",
: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.",
: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.",
: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`.",
@ -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).",
: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_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.",
: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)",
@ -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)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
: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.",
: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.",
@ -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.",
: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.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
# axis args
: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_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).",
: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)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins)
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
const _histogram_like = [:histogram, :barhist, :barbins]
const _line_like = [:line, :path, :steppre, :steppost]
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(series::Series) = is3d(series.d)
@ -163,6 +167,32 @@ const _scaleAliases = Dict{Symbol,Symbol}(
: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(
@ -172,7 +202,7 @@ const _series_defaults = KW(
:seriestype => :path,
:linestyle => :solid,
:linewidth => :auto,
:linecolor => :match,
:linecolor => :auto,
:linealpha => nothing,
:fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match,
@ -248,7 +278,6 @@ const _subplot_defaults = KW(
:background_color_inside => :match, # background inside grid
:foreground_color_subplot => :match, # default for other fg colors... match takes plot default
:foreground_color_legend => :match, # foreground of legend
:foreground_color_grid => :match, # grid color
:foreground_color_title => :match, # title color
:color_palette => :auto,
:legend => :best,
@ -256,7 +285,6 @@ const _subplot_defaults = KW(
:colorbar => :legend,
:clims => :auto,
:legendfont => font(8),
:grid => true,
:annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal
@ -267,6 +295,7 @@ const _subplot_defaults = KW(
:bottom_margin => :match,
:subplot_index => -1,
:colorbar_title => "",
:framestyle => :axes,
)
const _axis_defaults = KW(
@ -286,6 +315,11 @@ const _axis_defaults = KW(
:discrete_values => [],
:formatter => :auto,
:mirror => false,
:grid => true,
:foreground_color_grid => :match, # grid color
:gridalpha => 0.1,
:gridstyle => :solid,
:gridlinewidth => 0.5,
)
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,
:foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor)
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,
:foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor)
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(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
# series attributes
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(:inset_subplots, :inset, :floating)
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
@ -490,7 +528,6 @@ end
`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)`
"""
function default(k::Symbol)
k = get(_keyAliases, k, k)
for defaults in _all_defaults
@ -647,6 +684,36 @@ function processFillArg(d::KW, arg)
return
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(shapes::AVec) = map(_replace_markershape, shapes)
_replace_markershape(shape) = shape
@ -668,6 +735,7 @@ function preprocessArgs!(d::KW)
if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
d[:ticks] = nothing
d[:foreground_color_border] = RGBA(0,0,0,0)
d[:foreground_color_axis] = RGBA(0,0,0,0)
d[:grid] = false
delete!(d, :axis)
end
@ -690,6 +758,22 @@ function preprocessArgs!(d::KW)
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
for arg in wraptuple(pop!(d, :line, ()))
processLineArg(d, arg)
@ -754,6 +838,11 @@ function preprocessArgs!(d::KW)
d[:colorbar] = convertLegendValue(d[:colorbar])
end
# framestyle
if haskey(d, :framestyle) && haskey(_framestyleAliases, d[:framestyle])
d[:framestyle] = _framestyleAliases[d[:framestyle]]
end
# warnings for moved recipes
st = get(d, :seriestype, :path)
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
function extractGroupArgs(v::AVec, args...)
function extractGroupArgs(v::AVec, args...; legendEntry = string)
groupLabels = sort(collect(unique(v)))
n = length(groupLabels)
if n > 100
warn("You created n=$n groups... Is that intended?")
end
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
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"
function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...)
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)
end
@ -945,7 +1042,6 @@ const _match_map = KW(
:background_color_legend => :background_color_subplot,
:background_color_inside => :background_color_subplot,
:foreground_color_legend => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_title => :foreground_color_subplot,
:left_margin => :margin,
:top_margin => :margin,
@ -959,6 +1055,7 @@ const _match_map2 = KW(
:foreground_color_subplot => :foreground_color,
:foreground_color_axis => :foreground_color_subplot,
:foreground_color_border => :foreground_color_subplot,
:foreground_color_grid => :foreground_color_subplot,
:foreground_color_guide => :foreground_color_subplot,
:foreground_color_text => :foreground_color_subplot,
)
@ -1093,7 +1190,6 @@ function _update_subplot_colors(sp::Subplot)
# foreground colors
color_or_nothing!(sp.attr, :foreground_color_subplot)
color_or_nothing!(sp.attr, :foreground_color_legend)
color_or_nothing!(sp.attr, :foreground_color_grid)
color_or_nothing!(sp.attr, :foreground_color_title)
return
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_guide)
color_or_nothing!(axis.d, :foreground_color_text)
color_or_nothing!(axis.d, :foreground_color_grid)
return
end
@ -1250,12 +1347,14 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
# update other colors
for s in (:line, :marker, :fill)
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
sp[:foreground_color_subplot]
else
d[:seriescolor]
end, d[asym])
elseif d[csym] == :match
plot_color(d[:seriescolor], d[asym])
else
getSeriesRGBColor(d[csym], d[asym], sp, plotIndex)
end

View File

@ -181,15 +181,27 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
end
# get a list of well-laid-out ticks
scaled_ticks = if ticks == nothing
optimize_ticks(
if ticks == nothing
scaled_ticks = optimize_ticks(
sf(amin),
sf(amax);
k_min = 5, # minimum number of ticks
k_min = 4, # minimum number of ticks
k_max = 8, # maximum number of ticks
)[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
map(sf, filter(t -> amin <= t <= amax, ticks))
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end
unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
@ -216,7 +228,7 @@ end
# return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(axis::Axis)
ticks = axis[:ticks]
ticks = _transform_ticks(axis[:ticks])
ticks in (nothing, false) && return nothing
dvals = axis[:discrete_values]
@ -226,7 +238,7 @@ function get_ticks(axis::Axis)
elseif ticks == :auto
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
elseif typeof(ticks) <: AVec
elseif typeof(ticks) <: Union{AVec, Int}
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
elseif typeof(ticks) <: NTuple{2, Any}
@ -246,6 +258,10 @@ function get_ticks(axis::Axis)
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)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
spine_segs = Segments(2)
grid_segs = Segments(2)
xaxis_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))
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)))
if !(sp[:framestyle] == :none)
# xaxis
sp[:framestyle] == :grid || push!(xaxis_segs, (xmin,ymin), (xmax,ymin)) # bottom spine / xaxis
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin,ymax), (xmax,ymax)) # top spine
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
# push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
for xtick in xticks[1]
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid
# push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
for xtick in xticks[1]
push!(xaxis_segs, (xtick, ymin), (xtick, t1)) # bottom tick
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, t1), (xtick, t2)) # vertical grid
end
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
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)))
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
xticks, yticks, xaxis_segs, yaxis_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs
end

View File

@ -6,7 +6,10 @@ const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[]
const _initialized_backends = Set{Symbol}()
"Returns a list of supported backends"
backends() = _backends
"Returns the name of the current backend"
backend_name() = CURRENT_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,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :colorbar,
:marker_z,
:line_z,
:levels,
@ -38,7 +39,8 @@ const _glvisualize_attr = merge_with_base_supported([
:clims,
:inset_subplots,
:dpi,
:hover
:hover,
:framestyle,
])
const _glvisualize_seriestype = [
:path, :shape,
@ -676,17 +678,29 @@ function text_model(font, pivot)
end
end
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]
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 = []
if sp[:grid]
grid = draw_grid_lines(sp, grid_segs, 1f0, :dot, model, RGBA(c, 0.3f0))
if xaxis[:grid]
grid = draw_grid_lines(sp, xgrid_segs, xaxis[:gridlinewidth], xaxis[:gridstyle], model, RGBA(xgc, xaxis[:gridalpha]))
push!(axis_vis, grid)
end
if alpha(xaxis[:foreground_color_border]) > 0
spine = draw_grid_lines(sp, spine_segs, 1f0, :solid, model, RGBA(c, 1.0f0))
if yaxis[:grid]
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)
end
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)
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
mirror = xaxis[:mirror]
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))
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)
if sp[: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,
:guide, :lims, :ticks, :scale, :flip,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :levels,
:ribbon, :quiver,
:orientation,
@ -31,6 +32,7 @@ const _gr_attr = merge_with_base_supported([
:inset_subplots,
:bar_width,
:arrow,
:framestyle,
])
const _gr_seriestype = [
:path, :scatter,
@ -325,7 +327,10 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
cfuncind(ci)
GR.settransparency(_gr_gradient_alpha[ci-999])
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
@ -336,6 +341,7 @@ function gr_draw_markers(series::Series, x, y)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_draw_markers(series, x, y, series[:markersize], mz)
if mz != nothing
GR.setscale(0)
gr_colorbar(series[:subplot])
end
end
@ -537,40 +543,91 @@ function gr_display(plt::Plot)
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})
leftpad = 10mm
toppad = 2mm
rightpad = 2mm
bottompad = 6mm
if !haskey(ENV, "GKSwstype")
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
ENV["GKSwstype"] = "svg"
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] != ""
toppad += 5mm
end
if sp[:xaxis][:guide] != ""
xticks = axis_drawing_info(sp)[1]
if !(xticks in (nothing, false))
gr_set_font(sp[:xaxis][:tickfont],
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = :top,
color = sp[:xaxis][:foreground_color_axis],
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
# Add margin for x and y ticks
xticks, yticks = axis_drawing_info(sp)[1:2]
if !(xticks in (nothing, false))
flip, mirror = gr_set_xticks_font(sp)
l = gr_get_ticks_size(xticks, 2)
if mirror
toppad += 1mm + gr_plot_size[2] * l * px
else
bottompad += 4mm
bottompad += 1mm + gr_plot_size[2] * l * px
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] != ""
leftpad += 4mm
end
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
_update_min_padding!(sp)
# the viewports for this subplot
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)
@ -606,7 +663,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# TODO: can these be generic flags?
outside_ticks = false
cmap = false
draw_axes = true
draw_axes = sp[:framestyle] != :none
# axes_2d = true
for series in series_list(sp)
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])
# GR.setlinetype(GR.LINETYPE_DOTTED)
if sp[:grid]
GR.grid3d(xtick, 0, ztick, xmin, ymax, zmin, 2, 0, 2)
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
end
xaxis[:grid] && GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0)
yaxis[:grid] && GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
zaxis[:grid] && GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2)
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -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)
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
# draw the grid lines
if sp[:grid]
if xaxis[:grid]
# gr_set_linecolor(sp[:foreground_color_grid])
# GR.grid(xtick, ytick, 0, 0, majorx, majory)
gr_set_line(1, :dot, sp[:foreground_color_grid])
GR.settransparency(0.5)
gr_polyline(coords(grid_segs)...)
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
GR.settransparency(xaxis[:gridalpha])
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
GR.settransparency(1.0)
# spine (border) and tick marks
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
# axis lines
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
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)
if !(xticks in (nothing, false))
# tick marks
if !(xticks in (:none, nothing, false))
# x labels
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])
flip, mirror = gr_set_xticks_font(sp)
for (cv, dv) in zip(xticks...)
# use xor ($) to get the right y coords
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
if !(yticks in (nothing, false))
if !(yticks in (:none, nothing, false))
# y labels
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])
flip, mirror = gr_set_yticks_font(sp)
for (cv, dv) in zip(yticks...)
# use xor ($) to get the right y coords
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))
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
@ -863,7 +927,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if series[:marker_z] != nothing
zmin, zmax = extrema(series[:marker_z])
GR.setspace(zmin, zmax, 0, 90)
GR.setscale(0)
end
gr_draw_markers(series, x, y)
end
@ -1088,7 +1151,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
st = series[:seriestype]
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])
l, r = xpos-0.07, xpos-0.01
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([
:annotations,
: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,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
@ -334,15 +335,18 @@ end
# ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
const gridon = InspectDR.GridRect(vmajor=true, hmajor=true)
const gridoff = InspectDR.GridRect()
const plot = sp.o
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]
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)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(xaxis)

View File

@ -98,7 +98,7 @@ const _pgf_series_extrastyle = KW(
: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
const _pgf_annotation_halign = KW(
:center => "",
@ -121,7 +121,7 @@ function pgf_color(grad::ColorGradient)
end
# 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
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
end,", ")
@ -266,6 +266,11 @@ function pgf_axis(sp::Subplot, letter)
push!(style, "$(letter)majorticks=false")
end
# grid on or off
if axis[:grid]
push!(style, "$(letter)majorgrids = true")
end
# limits
# TODO: support zlims
if letter != :z
@ -324,7 +329,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:title] = "$(sp[:title])"
end
sp[:grid] && push!(style, "grid = major")
if sp[:aspect_ratio] in (1, :equal)
kw[:axisEqual] = "true"
end
@ -360,7 +364,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:colorbar] = "true"
end
# goto is needed to break out of col and series for
@goto colorbar_end
@goto colorbar_end
end
end
end

View File

@ -5,7 +5,7 @@ const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
: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_title,
:label,
@ -19,7 +19,8 @@ const _plotly_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar, :colorbar_title,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :levels,
:ribbon, :quiver,
:orientation,
@ -213,7 +214,9 @@ function plotly_axis(axis::Axis, sp::Subplot)
letter = axis[:letter]
ax = KW(
: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,
:ticks => "inside",
)
@ -229,8 +232,8 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
ax[:tickcolor] = rgba_string(axis[:foreground_color_border])
ax[:linecolor] = rgba_string(axis[:foreground_color_border])
ax[:tickcolor] = rgba_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# lims
lims = axis[:lims]
@ -435,7 +438,8 @@ function plotly_series(plt::Plot, series::Series)
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
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
if st in (:heatmap, :contour, :surface, :wireframe)
@ -459,7 +463,7 @@ function plotly_series(plt::Plot, series::Series)
else
hasline ? "lines" : "none"
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[:fillcolor] = rgba_string(series[:fillcolor])
elseif isa(series[:fillrange], AbstractVector)
@ -584,11 +588,21 @@ function plotly_series(plt::Plot, series::Series)
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
# series, one for series being filled to) instead of one
d_out_fillrange = copy(d_out)
d_out_fillrange[:y] = series[:fillrange]
d_out_fillrange = deepcopy(d_out)
d_out_fillrange[:showlegend] = false
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
if isa(series[:fillrange], AbstractVector)
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]
else

View File

@ -17,7 +17,8 @@ const _pyplot_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
@ -32,6 +33,7 @@ const _pyplot_attr = merge_with_base_supported([
:dpi,
:colorbar_title,
:stride,
:framestyle,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape,
@ -1053,7 +1055,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
py_set_scale(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])
if get(axis.d, :flip, false)
ax[Symbol("invert_", letter, "axis")]()
@ -1065,9 +1068,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
lab[:set_family](axis[:tickfont].family)
lab[:set_rotation](axis[:rotation])
end
if sp[:grid]
fgcolor = py_color(sp[:foreground_color_grid])
pyaxis[:grid](true, color = fgcolor, linestyle = ":")
if axis[:grid] && !(ticks in (:none, nothing, false))
fgcolor = py_color(axis[:foreground_color_grid])
pyaxis[:grid](true,
color = fgcolor,
linestyle = py_linestyle(:line, axis[:gridstyle]),
linewidth = axis[:gridlinewidth],
alpha = axis[:gridalpha])
ax[:set_axisbelow](true)
end
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
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
py_drawfig(fig)
end

View File

@ -22,6 +22,13 @@ immutable Shape
# end
# end
end
"""
Shape(x, y)
Shape(vertices)
Construct a polygon to be plotted
"""
Shape(verts::AVec) = Shape(unzip(verts)...)
Shape(s::Shape) = deepcopy(s)
@ -32,6 +39,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
#deprecated
@deprecate shape_coords coords
"return the vertex points from a Shape or Segments object"
function coords(shape::Shape)
shape.x, shape.y
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
"return the centroid of a Shape"
function center(shape::Shape)
x, y = coords(shape)
n = length(x)
@ -189,6 +198,7 @@ function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
scale!(shapecopy, x, y, c)
end
"translate a Shape in space"
function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape)
for i=1:length(sx)
@ -227,6 +237,7 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
shape
end
"rotate an object in space"
function rotate(shape::Shape, Θ::Real, c = center(shape))
shapecopy = deepcopy(shape)
rotate!(shapecopy, Θ, c)
@ -331,6 +342,11 @@ immutable PlotText
end
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(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
@ -350,6 +366,11 @@ immutable Stroke
style
end
"""
stroke(args...; alpha = nothing)
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing)
width = 1
color = :black
@ -597,6 +618,12 @@ immutable Arrow
headwidth::Float64
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...)
style = :simple
side = :head
@ -652,7 +679,7 @@ immutable Formatted{T}
end
# -----------------------------------------------------------------------
"create a BezierCurve for plotting"
type BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T}
end

View File

@ -155,7 +155,7 @@ PlotExample("Subplots",
""",
[:(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=false)
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=:none)
end)]
),
@ -290,7 +290,7 @@ PlotExample("Layouts, margins, label rotation, title location",
[:(begin
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
title_location=:left, left_margin=[20mm 0mm],
bottom_margin=50px, xrotation=60)
bottom_margin=10px, xrotation=60)
end)]
),
@ -321,7 +321,7 @@ PlotExample("Animation with subplots",
),
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
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))
@ -329,6 +329,26 @@ PlotExample("Spy",
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
# 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

View File

@ -133,7 +133,12 @@ make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h
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...)
oargs = vcat(oarg1, originargs...)
orighor = :left
@ -253,6 +258,13 @@ type GridLayout <: AbstractLayout
attr::KW
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...)
function GridLayout(dims...;

View File

@ -97,6 +97,13 @@ function addExtension(fn::AbstractString, ext::AbstractString)
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)
# 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)
# IJulia only... inline display
@ -198,6 +209,7 @@ for mime in keys(_mimeformats)
end
end
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
@ -266,6 +278,7 @@ using Requires
show(io, MIME("text/html"), plt)
end
ENV["MPLBACKEND"] = "Agg"
set_ijulia_output("text/html")
end
end

View File

@ -60,29 +60,26 @@ function _process_userrecipes(plt::Plot, d::KW, args)
args = _preprocess_args(d, args, still_to_process)
# 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.
# 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
# for processing.
# finished (no more args) get added to the kw_list, the ones that are not
# are placed on top of the stack and are then processed further.
kw_list = KW[]
while !isempty(still_to_process)
# grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes)
# grab the first in line to be processed and either add it to the kw_list or
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
# for further processing.
next_series = shift!(still_to_process)
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
for recipedata in rd_list
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(recipedata) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
end
if isempty(recipedata.args)
_process_userrecipe(plt, kw_list, recipedata)
else
# args are non-empty, so there's still processing to do... add it back to the queue
push!(still_to_process, recipedata)
end
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(next_series) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
end
if isempty(next_series.args)
_process_userrecipe(plt, kw_list, next_series)
else
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
prepend!(still_to_process,rd_list)
end
end
@ -213,7 +210,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# TODO: init subplots here
_update_plot_args(plt, d)
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
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)
"""
current()
Returns the Plot object for the current plot
"""
function current()
if isplotnull()
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")
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()
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
end

View File

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

View File

@ -509,12 +509,25 @@ end
# nothing
# 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
@recipe function f(groupby::GroupBy, args...)
lengthGroup = maximum(union(groupby.groupIds...))
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
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
end
end

View File

@ -13,6 +13,11 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
)
end
"""
plotarea(subplot)
Return the bounding box of a subplot
"""
plotarea(sp::Subplot) = sp.plotarea
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...)
# reset?
if s == :none || s == :default

View File

@ -137,7 +137,7 @@ function imageHack(d::KW)
end
# ---------------------------------------------------------------
"Build line segments for plotting"
type Segments{T}
pts::Vector{T}
end
@ -185,6 +185,7 @@ type SegmentsIterator
args::Tuple
n::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
@ -495,14 +496,42 @@ function make_fillrange_from_ribbon(kw::KW)
rib1, rib2 = -first(rib), last(rib)
# kw[:ribbon] = nothing
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
function get_sp_lims(sp::Subplot, letter::Symbol)
axis_limits(sp[Symbol(letter, :axis)])
end
"""
xlims([plt])
Returns the x axis limits of the current plot or subplot
"""
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)
"""
zlims([plt])
Returns the z axis limits of the current plot or subplot
"""
zlims(sp::Subplot) = get_sp_lims(sp, :z)
xlims(plt::Plot, sp_idx::Int = 1) = xlims(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])
@ -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:
```
with(:gadfly, size=(400,400), type=:histogram) do
with(:gr, size=(400,400), type=:histogram) do
plot(rand(10))
plot(rand(10))
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
# 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)
@ -42,7 +42,8 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
fn = "ref$idx.png"
# 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)
# @show refdir fn versions

View File

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