Merge branch 'master' into add-stride
This commit is contained in:
commit
c7eb22021f
13
NEWS.md
13
NEWS.md
@ -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
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Plots
|
||||
|
||||
[](https://travis-ci.org/JuliaPlots/Plots.jl)
|
||||
[](https://ci.appveyor.com/project/tbreloff/plots-jl)
|
||||
[](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@ -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"
|
||||
|
||||
|
||||
40
src/Plots.jl
40
src/Plots.jl
@ -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...)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)",
|
||||
)
|
||||
|
||||
127
src/args.jl
127
src/args.jl
@ -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
|
||||
|
||||
94
src/axes.jl
94
src/axes.jl
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
|
||||
@ -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])
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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...;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
"""
|
||||
theme(s::Symbol)
|
||||
|
||||
Specify the colour theme for plots.
|
||||
"""
|
||||
function theme(s::Symbol; kw...)
|
||||
# reset?
|
||||
if s == :none || s == :default
|
||||
|
||||
33
src/utils.jl
33
src/utils.jl
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user