Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 233f4d4465 | |||
| 1e3783b4dc | |||
| c355e02a20 | |||
| e178dca167 | |||
| 8beee23e21 | |||
| de32b02c75 | |||
| e3cba22ab7 | |||
| 25bcc3cbc1 | |||
| ca5310025f | |||
| 5b9561c13e | |||
| d594ac2f00 | |||
| 5157089d87 | |||
| d5b455b1f9 | |||
| 6cb1ed6c92 | |||
| 3d0d52f82a | |||
| be04828d35 | |||
| 5f9aa2edc0 | |||
| a5751895f0 | |||
| 78b0918216 | |||
| 5a7ed24078 | |||
| 509f8f6a95 | |||
| 6f3301e82f | |||
| 80f11ce30b | |||
| 95a6d24111 | |||
| 1fc2c511af | |||
| 3bcaac7051 | |||
| 25afd5c0e7 | |||
| dbbbeddad0 | |||
| c0f274d54b | |||
| 7816e078b5 | |||
| 56bda82529 | |||
| 54adc34348 | |||
| a4ed700338 | |||
| e2d107a70b | |||
| 31f080e4f4 | |||
| 6e4b9af6b1 | |||
| d301d2a06b | |||
| 2bbd4cbb17 | |||
| 5a2d39320f | |||
| 91158b1c20 | |||
| 06115f25ba | |||
| b3b533db94 | |||
| e16125cb50 | |||
| eb0dbac0c1 | |||
| eb1d1876d3 | |||
| f751b1b7ff | |||
| 34f9cfaa02 | |||
| 6dba32bf99 | |||
| 9529246bfb | |||
| 25774ee4c3 | |||
| 1137513236 | |||
| c76855698e | |||
| be8c66adc9 | |||
| be4a374122 | |||
| d76a6d1c38 | |||
| 5945196a4f | |||
| e164ea4b46 | |||
| db3dca1d73 | |||
| eea30fa253 | |||
| b585a0ef61 | |||
| db82f22320 | |||
| 66ce38d948 | |||
| e61d435b00 | |||
| d0a8985800 | |||
| 4c1c092234 | |||
| f02079dafe | |||
| 4be0093a8a | |||
| 130eb778d3 | |||
| be177e0f80 | |||
| 42f54b8df9 | |||
| 4b60b05f75 | |||
| 6afd0f9f82 | |||
| 8288e85c25 | |||
| bb2f4ff16b | |||
| 682ba1f764 | |||
| e0c679f5ee | |||
| a1d0d028b6 | |||
| 33a15f1e93 | |||
| 23ae99b97e | |||
| 3c37de152d | |||
| 2dd99d053a | |||
| c60d66d94a | |||
| 6b814b8dca | |||
| 11c71d7a5d | |||
| d90b2e6142 | |||
| 2ab7f3c767 | |||
| a937fa0ef8 | |||
| bc36749f6d | |||
| 88d1735380 | |||
| 92672ffddf | |||
| 2ccfa9b4fa | |||
| 1f07be6ae0 | |||
| 9a8c7b290f | |||
| 2e3bc15d2b | |||
| 9f0117d914 | |||
| 5e5412887c | |||
| b2efd5150b | |||
| 50ec31a7a3 | |||
| 20bd9d6160 | |||
| 8c3c07acb7 | |||
| 26a56c3105 | |||
| d0070c72fd | |||
| 780f3c49e9 | |||
| 2c191dbdbf | |||
| 4b617f96a3 | |||
| dabc3f998b | |||
| 23a22102c5 | |||
| 8d9ff7af11 | |||
| fdcb6086d1 | |||
| 00e05efd7c | |||
| 0dd5eef3f2 | |||
| 6ecd30d42b | |||
| 317091639f | |||
| 9c8e879465 | |||
| dc5a04346a | |||
| 44b533f501 | |||
| 0fa459d590 | |||
| 96d34bb5ee | |||
| 9f712b44f3 | |||
| 1ff8663e44 | |||
| 52f042263b | |||
| da7e57989c | |||
| 65c3d90642 | |||
| 3c044d729d | |||
| 82ecf894c0 | |||
| 7b15f7d74b | |||
| 371406845c | |||
| ccd26a6d42 | |||
| e992930ff6 | |||
| f66d8bed8f | |||
| 155634ef34 | |||
| dbc7bc4253 | |||
| fc427e618a | |||
| 6d66190644 | |||
| 9b2da0d645 | |||
| 95c60b9554 | |||
| bc7f6a6fac | |||
| 0b1118540a | |||
| 96bd0bb46c | |||
| 33e97ee49b | |||
| 8414facde2 | |||
| 2a0d5a0a03 | |||
| aec30301a1 | |||
| 9cf246a03e | |||
| c385035ac5 | |||
| 409cf2c630 | |||
| 02ddbc8381 | |||
| 1c2a588864 | |||
| de043eeaa2 | |||
| 5e5f23b5e5 | |||
| d671ccd6ba | |||
| f4f2f09d17 | |||
| 2f1c70e49f | |||
| d9890498d1 | |||
| 46ae505bab | |||
| b0e84a68d0 | |||
| 356a5b6136 | |||
| e86193cebe | |||
| e35b2ec3ff | |||
| 69d421d785 | |||
| 47c51b28c1 | |||
| dd2653968e | |||
| b091d95eb2 | |||
| 33327d3992 | |||
| 027ce58655 | |||
| cd611ef4bf | |||
| bc7f5118ea | |||
| 53ae915044 | |||
| a47f14ec13 | |||
| 86149ba3a7 | |||
| cc3822b222 | |||
| 57b9602b13 | |||
| c9839dbefa | |||
| 5b6423ec6c | |||
| b3efcf9b68 | |||
| cadb0f96e2 | |||
| d3b825b49f | |||
| c808cbb4fa | |||
| dd526e00ab | |||
| bad2ef63c6 | |||
| 6cca763284 | |||
| 915c41c9d9 | |||
| 9c2c548874 | |||
| fdf699bf35 | |||
| e3ce1ab1d1 | |||
| af56d6f265 | |||
| 93d16a27c1 | |||
| a602309a02 | |||
| 11e9eb3aa3 |
@@ -9,8 +9,40 @@
|
||||
- `backports` branch is for Julia 0.4
|
||||
|
||||
---
|
||||
## (current master)
|
||||
|
||||
## 0.12 (current master/dev)
|
||||
## 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
|
||||
|
||||
- fix deprecation warnings
|
||||
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
|
||||
- drop FactCheck in tests
|
||||
- remove julia 0.5 compliant uses of transpose operator
|
||||
- fix GR heatmap bugs
|
||||
- fix GR guide padding
|
||||
- improve legend markers in GR
|
||||
- add surface alpha for Plotly(JS)
|
||||
- add fillrange to Plotly(JS)
|
||||
- allow usage of Matplotlib 1.5 with PyPlot
|
||||
- fix GLVisualize for julia 0.6
|
||||
- conform to changes in InspectDR
|
||||
|
||||
#### 0.12.0
|
||||
|
||||
- 0.6 only
|
||||
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
julia 0.6-pre
|
||||
julia 0.6
|
||||
|
||||
RecipesBase 0.2.0
|
||||
PlotUtils 0.4.1
|
||||
PlotThemes 0.1.3
|
||||
Reexport
|
||||
FixedSizeArrays
|
||||
StaticArrays 0.5
|
||||
FixedPointNumbers 0.3
|
||||
Measures
|
||||
Showoff
|
||||
StatsBase 0.14.0
|
||||
JSON
|
||||
NaNMath
|
||||
Requires
|
||||
Contour
|
||||
|
||||
+8
-2
@@ -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"
|
||||
|
||||
|
||||
+46
-10
@@ -1,11 +1,14 @@
|
||||
__precompile__(false)
|
||||
__precompile__(true)
|
||||
|
||||
module Plots
|
||||
|
||||
using Reexport
|
||||
using FixedSizeArrays
|
||||
|
||||
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
|
||||
@@ -49,6 +52,8 @@ export
|
||||
yflip!,
|
||||
xaxis!,
|
||||
yaxis!,
|
||||
xgrid!,
|
||||
ygrid!,
|
||||
|
||||
xlims,
|
||||
ylims,
|
||||
@@ -148,12 +153,11 @@ include("layouts.jl")
|
||||
include("subplots.jl")
|
||||
include("recipes.jl")
|
||||
include("animation.jl")
|
||||
include("output.jl")
|
||||
include("examples.jl")
|
||||
include("arg_desc.jl")
|
||||
include("plotattr.jl")
|
||||
include("backends.jl")
|
||||
|
||||
include("output.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -184,33 +188,65 @@ include("backends.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...)
|
||||
@@ -228,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...)
|
||||
@@ -241,10 +279,8 @@ end
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
function __init__()
|
||||
setup_ijulia()
|
||||
setup_atom()
|
||||
|
||||
# for compatibility with Requires.jl:
|
||||
@init begin
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
default(k, v)
|
||||
|
||||
+7
-2
@@ -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
|
||||
|
||||
+6
-3
@@ -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)",
|
||||
)
|
||||
|
||||
+115
-12
@@ -163,6 +163,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 +198,7 @@ const _series_defaults = KW(
|
||||
:seriestype => :path,
|
||||
:linestyle => :solid,
|
||||
:linewidth => :auto,
|
||||
:linecolor => :match,
|
||||
:linecolor => :auto,
|
||||
:linealpha => nothing,
|
||||
:fillrange => nothing, # ribbons, areas, etc
|
||||
:fillcolor => :match,
|
||||
@@ -247,7 +273,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,
|
||||
@@ -255,7 +280,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
|
||||
@@ -266,6 +290,7 @@ const _subplot_defaults = KW(
|
||||
:bottom_margin => :match,
|
||||
:subplot_index => -1,
|
||||
:colorbar_title => "",
|
||||
:framestyle => :axes,
|
||||
)
|
||||
|
||||
const _axis_defaults = KW(
|
||||
@@ -285,6 +310,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}([
|
||||
@@ -336,6 +366,12 @@ const _all_defaults = KW[
|
||||
_axis_defaults_byletter
|
||||
]
|
||||
|
||||
# to be able to reset font sizes to initial values
|
||||
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefont].pointsize,
|
||||
:legendfont => _subplot_defaults[:legendfont].pointsize,
|
||||
:tickfont => _axis_defaults[:tickfont].pointsize,
|
||||
:guidefont => _axis_defaults[:guidefont].pointsize)
|
||||
|
||||
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
|
||||
|
||||
RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
|
||||
@@ -396,7 +432,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,
|
||||
@@ -408,6 +444,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)
|
||||
@@ -463,6 +500,9 @@ add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesa
|
||||
add_aliases(:html_output_format, :format, :fmt, :html_format)
|
||||
add_aliases(:orientation, :direction, :dir)
|
||||
add_aliases(:inset_subplots, :inset, :floating)
|
||||
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
|
||||
@@ -482,7 +522,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
|
||||
@@ -522,7 +561,6 @@ function default(d::KW, k::Symbol)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# if arg is a valid color value, then set d[csym] and return true
|
||||
@@ -640,6 +678,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
|
||||
@@ -661,6 +729,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
|
||||
@@ -683,6 +752,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)
|
||||
@@ -701,6 +786,9 @@ function preprocessArgs!(d::KW)
|
||||
delete!(d, :marker)
|
||||
if haskey(d, :markershape)
|
||||
d[:markershape] = _replace_markershape(d[:markershape])
|
||||
if d[:markershape] == :none && d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
elseif anymarker
|
||||
d[:markershape_to_add] = :circle # add it after _apply_recipe
|
||||
end
|
||||
@@ -744,6 +832,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)
|
||||
@@ -763,21 +856,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
|
||||
|
||||
@@ -935,7 +1036,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,
|
||||
@@ -949,6 +1049,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,
|
||||
)
|
||||
@@ -1083,7 +1184,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
|
||||
@@ -1135,6 +1235,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
|
||||
|
||||
@@ -1240,12 +1341,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
|
||||
|
||||
+59
-35
@@ -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")
|
||||
|
||||
|
||||
+55
-39
@@ -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,
|
||||
@@ -58,7 +60,7 @@ const _glvisualize_scale = [:identity, :ln, :log2, :log10]
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval begin
|
||||
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
|
||||
import FileIO, Images
|
||||
export GLVisualize
|
||||
import Reactive: Signal
|
||||
@@ -66,9 +68,8 @@ function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
import GLVisualize: visualize
|
||||
import Plots.GL
|
||||
import UnicodeFun
|
||||
Plots.slice_arg(img::Images.AbstractImage, idx::Int) = img
|
||||
Plots.slice_arg{C<:Colorant}(img::Matrix{C}, idx::Int) = img
|
||||
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
|
||||
is_marker_supported{Img<:Images.AbstractImage}(::GLVisualizeBackend, shape::Union{Vector{Img}, Img}) = true
|
||||
is_marker_supported{C<:Colorant}(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) = true
|
||||
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
|
||||
const GL = Plots
|
||||
@@ -173,12 +174,12 @@ function gl_marker(shape)
|
||||
shape
|
||||
end
|
||||
function gl_marker(shape::Shape)
|
||||
points = Point2f0[Vec{2,Float32}(p) for p in zip(shape.x, shape.y)]
|
||||
points = Point2f0[GeometryTypes.Vec{2, Float32}(p) for p in zip(shape.x, shape.y)]
|
||||
bb = GeometryTypes.AABB(points)
|
||||
mini, maxi = minimum(bb), maximum(bb)
|
||||
w3 = maxi-mini
|
||||
origin, width = Point2f0(mini[1], mini[2]), Point2f0(w3[1], w3[2])
|
||||
map!(p -> ((p - origin) ./ width) - 0.5f0, points) # normalize and center
|
||||
map!(p -> ((p - origin) ./ width) - 0.5f0, points, points) # normalize and center
|
||||
GeometryTypes.GLNormalMesh(points)
|
||||
end
|
||||
# create a marker/shape type
|
||||
@@ -212,13 +213,13 @@ function extract_limits(sp, d, kw_args)
|
||||
nothing
|
||||
end
|
||||
|
||||
to_vec{T <: FixedVector}(::Type{T}, vec::T) = vec
|
||||
to_vec{T <: FixedVector}(::Type{T}, s::Number) = T(s)
|
||||
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vec::T) = vec
|
||||
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, s::Number) = T(s)
|
||||
|
||||
to_vec{T <: FixedVector{2}}(::Type{T}, vec::FixedVector{3}) = T(vec[1], vec[2])
|
||||
to_vec{T <: FixedVector{3}}(::Type{T}, vec::FixedVector{2}) = T(vec[1], vec[2], 0)
|
||||
to_vec{T <: StaticArrays.StaticVector{2}}(::Type{T}, vec::StaticArrays.StaticVector{3}) = T(vec[1], vec[2])
|
||||
to_vec{T <: StaticArrays.StaticVector{3}}(::Type{T}, vec::StaticArrays.StaticVector{2}) = T(vec[1], vec[2], 0)
|
||||
|
||||
to_vec{T <: FixedVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
|
||||
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
|
||||
|
||||
function extract_marker(d, kw_args)
|
||||
dim = Plots.is3d(d) ? 3 : 2
|
||||
@@ -274,7 +275,7 @@ function extract_surface(d)
|
||||
map(_extract_surface, (d[:x], d[:y], d[:z]))
|
||||
end
|
||||
function topoints{P}(::Type{P}, array)
|
||||
P[x for x in zip(array...)]
|
||||
[P(x) for x in zip(array...)]
|
||||
end
|
||||
function extract_points(d)
|
||||
dim = is3d(d) ? 3 : 2
|
||||
@@ -576,8 +577,10 @@ end
|
||||
|
||||
function align_offset(startpos, lastpos, atlas, rscale, font, align)
|
||||
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
|
||||
xmove = (lastpos-startpos)[1]+xscale
|
||||
if align == :top
|
||||
xmove = (lastpos-startpos)[1] + xscale
|
||||
if isa(align, GeometryTypes.Vec)
|
||||
return -Vec2f0(xmove, yscale) .* align
|
||||
elseif align == :top
|
||||
return -Vec2f0(xmove/2f0, yscale)
|
||||
elseif align == :right
|
||||
return -Vec2f0(xmove, yscale/2f0)
|
||||
@@ -586,11 +589,6 @@ function align_offset(startpos, lastpos, atlas, rscale, font, align)
|
||||
end
|
||||
end
|
||||
|
||||
function align_offset(startpos, lastpos, atlas, rscale, font, align::Vec)
|
||||
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
|
||||
xmove = (lastpos-startpos)[1] + xscale
|
||||
return -Vec2f0(xmove, yscale) .* align
|
||||
end
|
||||
|
||||
function alignment2num(x::Symbol)
|
||||
(x in (:hcenter, :vcenter)) && return 0.5
|
||||
@@ -638,7 +636,7 @@ function draw_ticks(
|
||||
position = GLVisualize.calc_position(str, startpos, sz, font, atlas)
|
||||
offset = GLVisualize.calc_offset(str, sz, font, atlas)
|
||||
alignoff = align_offset(startpos, last(position), atlas, sz, font, align)
|
||||
map!(position) do pos
|
||||
map!(position, position) do pos
|
||||
pos .+ alignoff
|
||||
end
|
||||
append!(positions, position)
|
||||
@@ -660,7 +658,7 @@ function glvisualize_text(position, text, kw_args)
|
||||
offset = GLVisualize.calc_offset(text.str, rscale, font, atlas)
|
||||
alignoff = align_offset(startpos, last(position), atlas, rscale, font, text_align)
|
||||
|
||||
map!(position) do pos
|
||||
map!(position, position) do pos
|
||||
pos .+ alignoff
|
||||
end
|
||||
kw_args[:position] = position
|
||||
@@ -680,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])
|
||||
@@ -698,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)
|
||||
@@ -718,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])
|
||||
@@ -792,7 +811,7 @@ function gl_bar(d, kw_args)
|
||||
fillto = 0
|
||||
end
|
||||
# create the bar shapes by adding x/y segments
|
||||
positions, scales = Array(Point2f0, ny), Array(Vec2f0, ny)
|
||||
positions, scales = Array{Point2f0}(ny), Array{Vec2f0}(ny)
|
||||
m = Reactive.value(kw_args[:model])
|
||||
sx, sy = m[1,1], m[2,2]
|
||||
for i=1:ny
|
||||
@@ -943,7 +962,7 @@ function scale_for_annotations!(series::Series, scaletype::Symbol = :pixels)
|
||||
# we use baseshape to overwrite the markershape attribute
|
||||
# with a list of custom shapes for each
|
||||
msw, msh = anns.scalefactor
|
||||
offsets = Array(Vec2f0, length(anns.strs))
|
||||
offsets = Array{Vec2f0}(length(anns.strs))
|
||||
series[:markersize] = map(1:length(anns.strs)) do i
|
||||
str = _cycle(anns.strs, i)
|
||||
# get the width and height of the string (in mm)
|
||||
@@ -1122,7 +1141,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||
anns = series[:series_annotations]
|
||||
for (x, y, str, font) in EachAnn(anns, d[:x], d[:y])
|
||||
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
|
||||
x, y = Reactive.value(model_m) * Vec{4, Float32}(x, y, 0, 1)
|
||||
x, y = Reactive.value(model_m) * GeometryTypes.Vec{4, Float32}(x, y, 0, 1)
|
||||
extract_font(font, txt_args)
|
||||
t = glvisualize_text(Point2f0(x, y), PlotText(str, font), txt_args)
|
||||
GLVisualize._view(t, sp_screen, camera = :perspective)
|
||||
@@ -1148,10 +1167,7 @@ function _show(io::IO, ::MIME"image/png", plt::Plot{GLVisualizeBackend})
|
||||
GLWindow.render_frame(GLWindow.rootscreen(plt.o))
|
||||
GLWindow.swapbuffers(plt.o)
|
||||
buff = GLWindow.screenbuffer(plt.o)
|
||||
png = Images.Image(map(RGB{U8}, buff),
|
||||
colorspace = "sRGB",
|
||||
spatialorder = ["y", "x"]
|
||||
)
|
||||
png = map(RGB{U8}, buff)
|
||||
FileIO.save(FileIO.Stream(FileIO.DataFormat{:PNG}, io), png)
|
||||
end
|
||||
|
||||
@@ -1309,8 +1325,8 @@ function gl_contour(x, y, z, kw_args)
|
||||
if kw_args[:fillrange] != nothing
|
||||
|
||||
delete!(kw_args, :intensity)
|
||||
I = GLVisualize.Intensity{1, Float32}
|
||||
main = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
|
||||
I = GLVisualize.Intensity{Float32}
|
||||
main = [I(z[j,i]) for i=1:size(z, 2), j=1:size(z, 1)]
|
||||
return visualize(main, Style(:default), kw_args)
|
||||
|
||||
else
|
||||
@@ -1342,7 +1358,7 @@ function gl_heatmap(x,y,z, kw_args)
|
||||
get!(kw_args, :color_norm, Vec2f0(ignorenan_extrema(z)))
|
||||
get!(kw_args, :color_map, Plots.make_gradient(cgrad()))
|
||||
delete!(kw_args, :intensity)
|
||||
I = GLVisualize.Intensity{1, Float32}
|
||||
I = GLVisualize.Intensity{Float32}
|
||||
heatmap = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
|
||||
tex = GLAbstraction.Texture(heatmap, minfilter=:nearest)
|
||||
kw_args[:stroke_width] = 0f0
|
||||
|
||||
+157
-44
@@ -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,
|
||||
@@ -179,7 +181,7 @@ gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
|
||||
function gr_inqtext(x, y, s)
|
||||
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
|
||||
GR.inqtextext(x, y, s[2:end-1])
|
||||
elseif search(s, '\\') != 0 || search(s, '_') != 0 || search(s, '^') != 0
|
||||
elseif search(s, '\\') != 0
|
||||
GR.inqtextext(x, y, s)
|
||||
else
|
||||
GR.inqtext(x, y, s)
|
||||
@@ -191,7 +193,7 @@ gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
|
||||
function gr_text(x, y, s)
|
||||
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
|
||||
GR.mathtex(x, y, s[2:end-1])
|
||||
elseif search(s, '\\') != 0 || search(s, '_') != 0 || search(s, '^') != 0
|
||||
elseif search(s, '\\') != 0
|
||||
GR.textext(x, y, s)
|
||||
else
|
||||
GR.text(x, y, s)
|
||||
@@ -272,6 +274,10 @@ function normalize_zvals(zv::AVec)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
gr_alpha(α::Void) = 1
|
||||
gr_alpha(α::Real) = α
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# draw ONE Shape
|
||||
@@ -321,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
|
||||
@@ -332,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
|
||||
@@ -353,7 +363,7 @@ function gr_set_fill(c) #, a)
|
||||
end
|
||||
|
||||
# this stores the conversion from a font pointsize to "percentage of window height" (which is what GR uses)
|
||||
const _gr_point_mult = zeros(1)
|
||||
const _gr_point_mult = 0.0018 * ones(1)
|
||||
|
||||
# set the font attributes... assumes _gr_point_mult has been populated already
|
||||
function gr_set_font(f::Font; halign = f.halign, valign = f.valign,
|
||||
@@ -384,7 +394,7 @@ end
|
||||
const viewport_plotarea = zeros(4)
|
||||
|
||||
# the size of the current plot in pixels
|
||||
const gr_plot_size = zeros(2)
|
||||
const gr_plot_size = [600.0, 400.0]
|
||||
|
||||
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
|
||||
viewport = zeros(4)
|
||||
@@ -533,17 +543,95 @@ function gr_display(plt::Plot)
|
||||
end
|
||||
|
||||
|
||||
function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
sp.minpad = (10mm,2mm,2mm,8mm)
|
||||
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})
|
||||
if !haskey(ENV, "GKSwstype") && isijulia()
|
||||
ENV["GKSwstype"] = "svg"
|
||||
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
|
||||
# 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 += 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)
|
||||
# get data limits
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
xy_lims = data_lims
|
||||
|
||||
ratio = sp[:aspect_ratio]
|
||||
if ratio != :none
|
||||
@@ -573,7 +661,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]
|
||||
@@ -585,7 +673,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
if st == :heatmap
|
||||
outside_ticks = true
|
||||
x, y = heatmap_edges(series[:x]), heatmap_edges(series[:y])
|
||||
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale])
|
||||
xy_lims = x[1], x[end], y[1], y[end]
|
||||
expand_extrema!(sp[:xaxis], x)
|
||||
expand_extrema!(sp[:yaxis], y)
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
@@ -657,10 +746,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)
|
||||
|
||||
@@ -675,34 +763,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)
|
||||
@@ -711,15 +802,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)
|
||||
@@ -727,6 +812,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
|
||||
|
||||
@@ -826,6 +922,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
|
||||
if series[:markershape] != :none
|
||||
if series[:marker_z] != nothing
|
||||
zmin, zmax = extrema(series[:marker_z])
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
end
|
||||
gr_draw_markers(series, x, y)
|
||||
end
|
||||
|
||||
@@ -851,7 +951,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
# create the colorbar of contour levels
|
||||
if sp[:colorbar] != :none
|
||||
gr_set_viewport_cmap(sp)
|
||||
l = round(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
|
||||
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
|
||||
GR.setwindow(xmin, xmax, zmin, zmax)
|
||||
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
|
||||
ztick = 0.5 * GR.tick(zmin, zmax)
|
||||
@@ -873,6 +973,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
cmap && gr_colorbar(sp)
|
||||
|
||||
elseif st == :heatmap
|
||||
xmin, xmax, ymin, ymax = xy_lims
|
||||
zmin, zmax = gr_lims(zaxis, true)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
@@ -886,7 +987,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
round(Int, blue(c) * 255) << 16 +
|
||||
round(Int, green(c) * 255) << 8 +
|
||||
round(Int, red(c) * 255) ), colors)
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, length(x), length(y), rgba)
|
||||
w, h = length(x), length(y)
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||
cmap && gr_colorbar(sp)
|
||||
|
||||
elseif st in (:path3d, :scatter3d)
|
||||
@@ -1038,6 +1140,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
if sp[:legendtitle] != nothing
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
|
||||
gr_set_textcolor(sp[:foreground_color_legend])
|
||||
GR.settransparency(1)
|
||||
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
|
||||
ypos -= dy
|
||||
end
|
||||
@@ -1045,16 +1148,26 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
should_add_to_legend(series) || continue
|
||||
st = series[:seriestype]
|
||||
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
|
||||
if st == :path && series[:fillrange] == nothing
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
|
||||
elseif 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
|
||||
x = [l, r, r, l, l]
|
||||
y = [b, b, t, t, b]
|
||||
GR.settransparency(gr_alpha(series[:fillalpha]))
|
||||
gr_polyline(x, y, GR.fillarea)
|
||||
gr_polyline(x, y)
|
||||
GR.settransparency(gr_alpha(series[:linealpha]))
|
||||
st == :shape && gr_polyline(x, y)
|
||||
end
|
||||
|
||||
if st == :path
|
||||
GR.settransparency(gr_alpha(series[:linealpha]))
|
||||
if series[:fillrange] == nothing || series[:ribbon] != nothing
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
|
||||
else
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos+0.4dy, ypos+0.4dy])
|
||||
end
|
||||
end
|
||||
|
||||
if series[:markershape] != :none
|
||||
|
||||
+28
-25
@@ -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)
|
||||
@@ -362,30 +366,29 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
|
||||
|
||||
l = plot.layout
|
||||
l.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l.framedata.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l.framedata.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l.fnttitle = InspectDR.Font(sp[:titlefont].family,
|
||||
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l[:font_title] = InspectDR.Font(sp[:titlefont].family,
|
||||
_inspectdr_mapptsize(sp[:titlefont].pointsize),
|
||||
color = _inspectdr_mapcolor(sp[:foreground_color_title])
|
||||
)
|
||||
#Cannot independently control fonts of axes with InspectDR:
|
||||
l.fntaxlabel = InspectDR.Font(xaxis[:guidefont].family,
|
||||
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefont].family,
|
||||
_inspectdr_mapptsize(xaxis[:guidefont].pointsize),
|
||||
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide])
|
||||
)
|
||||
l.fntticklabel = InspectDR.Font(xaxis[:tickfont].family,
|
||||
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfont].family,
|
||||
_inspectdr_mapptsize(xaxis[:tickfont].pointsize),
|
||||
color = _inspectdr_mapcolor(xaxis[:foreground_color_text])
|
||||
)
|
||||
leg = l.legend
|
||||
leg.enabled = (sp[:legend] != :none)
|
||||
#leg.width = 150 #TODO: compute???
|
||||
leg.font = InspectDR.Font(sp[:legendfont].family,
|
||||
l[:enable_legend] = (sp[:legend] != :none)
|
||||
#l[:halloc_legend] = 150 #TODO: compute???
|
||||
l[:font_legend] = InspectDR.Font(sp[:legendfont].family,
|
||||
_inspectdr_mapptsize(sp[:legendfont].pointsize),
|
||||
color = _inspectdr_mapcolor(sp[:foreground_color_legend])
|
||||
)
|
||||
leg.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
end
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
@@ -399,7 +402,7 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
#Don't use window_title... probably not what you want.
|
||||
#mplot.title = plt[:window_title]
|
||||
end
|
||||
mplot.frame.fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
|
||||
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
|
||||
|
||||
resize!(mplot.subplots, length(plt.subplots))
|
||||
nsubplots = length(plt.subplots)
|
||||
@@ -421,15 +424,15 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
#Do not yet support absolute plot positionning.
|
||||
#Just try to make things look more-or less ok:
|
||||
if nsubplots <= 1
|
||||
mplot.ncolumns = 1
|
||||
mplot.layout[:ncolumns] = 1
|
||||
elseif nsubplots <= 4
|
||||
mplot.ncolumns = 2
|
||||
mplot.layout[:ncolumns] = 2
|
||||
elseif nsubplots <= 6
|
||||
mplot.ncolumns = 3
|
||||
mplot.layout[:ncolumns] = 3
|
||||
elseif nsubplots <= 12
|
||||
mplot.ncolumns = 4
|
||||
mplot.layout[:ncolumns] = 4
|
||||
else
|
||||
mplot.ncolumns = 5
|
||||
mplot.layout[:ncolumns] = 5
|
||||
end
|
||||
|
||||
for series in plt.series_list
|
||||
@@ -446,7 +449,7 @@ function _update_min_padding!(sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
|
||||
#Computing plotbounds with 0-BoundingBox returns required padding:
|
||||
bb = InspectDR.plotbounds(plot.layout, InspectDR.BoundingBox(0,0,0,0))
|
||||
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
|
||||
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
|
||||
#TODO: possibly zero-out items not in use??
|
||||
|
||||
@@ -468,7 +471,7 @@ function _update_plot_object(plt::Plot{InspectDRBackend})
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
graphbb = _inspectdr_to_pixels(plotarea(sp))
|
||||
plot = mplot.subplots[i]
|
||||
plot.plotbb = InspectDR.plotbounds(plot.layout, graphbb)
|
||||
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
|
||||
end
|
||||
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
@@ -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
|
||||
|
||||
+43
-8
@@ -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,6 +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) || isa(series[:fillrange], Tuple))
|
||||
|
||||
# for surface types, set the data
|
||||
if st in (:heatmap, :contour, :surface, :wireframe)
|
||||
@@ -458,11 +463,14 @@ 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)
|
||||
d_out[:fill] = "tonexty"
|
||||
d_out[:fillcolor] = rgba_string(series[:fillcolor])
|
||||
elseif !(series[:fillrange] in (false, nothing))
|
||||
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(series[:fillrange])")
|
||||
warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
@@ -479,6 +487,7 @@ function plotly_series(plt::Plot, series::Series)
|
||||
d_out[:type] = "heatmap"
|
||||
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
|
||||
elseif st == :contour
|
||||
d_out[:type] = "contour"
|
||||
@@ -487,6 +496,7 @@ function plotly_series(plt::Plot, series::Series)
|
||||
d_out[:ncontours] = series[:levels]
|
||||
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
|
||||
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
d_out[:type] = "surface"
|
||||
@@ -499,11 +509,14 @@ function plotly_series(plt::Plot, series::Series)
|
||||
:highlightwidth => series[:linewidth],
|
||||
)
|
||||
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
|
||||
d_out[:showscale] = false
|
||||
else
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:opacity] = series[:fillalpha]
|
||||
if series[:fill_z] != nothing
|
||||
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
|
||||
end
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
end
|
||||
|
||||
elseif st == :pie
|
||||
@@ -572,7 +585,29 @@ function plotly_series(plt::Plot, series::Series)
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, series[:hover])
|
||||
|
||||
[d_out]
|
||||
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 = deepcopy(d_out)
|
||||
d_out_fillrange[:showlegend] = false
|
||||
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
|
||||
return [d_out]
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_series_shapes(plt::Plot, series::Series)
|
||||
|
||||
+72
-38
@@ -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,
|
||||
@@ -31,6 +32,7 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
:framestyle,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
:path, :steppre, :steppost, :shape,
|
||||
@@ -70,18 +72,26 @@ function _initialize_backend(::PyPlotBackend)
|
||||
append!(Base.Multimedia.displays, otherdisplays)
|
||||
|
||||
export PyPlot
|
||||
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
|
||||
const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
|
||||
const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
|
||||
const pypatches = PyPlot.pywrap(PyPlot.pyimport("matplotlib.patches"))
|
||||
const pyfont = PyPlot.pywrap(PyPlot.pyimport("matplotlib.font_manager"))
|
||||
const pyticker = PyPlot.pywrap(PyPlot.pyimport("matplotlib.ticker"))
|
||||
const pycmap = PyPlot.pywrap(PyPlot.pyimport("matplotlib.cm"))
|
||||
const pynp = PyPlot.pywrap(PyPlot.pyimport("numpy"))
|
||||
pynp.seterr(invalid="ignore")
|
||||
const pytransforms = PyPlot.pywrap(PyPlot.pyimport("matplotlib.transforms"))
|
||||
const pycollections = PyPlot.pywrap(PyPlot.pyimport("matplotlib.collections"))
|
||||
const pyart3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d.art3d"))
|
||||
const pycolors = PyPlot.pyimport("matplotlib.colors")
|
||||
const pypath = PyPlot.pyimport("matplotlib.path")
|
||||
const mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
|
||||
const pypatches = PyPlot.pyimport("matplotlib.patches")
|
||||
const pyfont = PyPlot.pyimport("matplotlib.font_manager")
|
||||
const pyticker = PyPlot.pyimport("matplotlib.ticker")
|
||||
const pycmap = PyPlot.pyimport("matplotlib.cm")
|
||||
const pynp = PyPlot.pyimport("numpy")
|
||||
pynp["seterr"](invalid="ignore")
|
||||
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
|
||||
const pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
const pyart3d = PyPlot.pyimport("mpl_toolkits.mplot3d.art3d")
|
||||
|
||||
# "support" matplotlib v1.5
|
||||
const set_facecolor_sym = if PyPlot.version < v"2"
|
||||
warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0")
|
||||
:set_axis_bgcolor
|
||||
else
|
||||
:set_facecolor
|
||||
end
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
@@ -101,7 +111,7 @@ end
|
||||
|
||||
# function py_colormap(c::ColorGradient, α=nothing)
|
||||
# pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values]
|
||||
# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
|
||||
# pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
# end
|
||||
|
||||
# # convert vectors and ColorVectors to standard ColorGradients
|
||||
@@ -118,7 +128,7 @@ py_color(grad::ColorGradient) = py_color(grad.colors)
|
||||
|
||||
function py_colormap(grad::ColorGradient)
|
||||
pyvals = [(z, py_color(grad[z])) for z in grad.values]
|
||||
cm = pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals)
|
||||
cm = pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
cm[:set_bad](color=(0,0,0,0.0), alpha=0.0)
|
||||
cm
|
||||
end
|
||||
@@ -127,7 +137,7 @@ py_colormap(c) = py_colormap(cgrad())
|
||||
|
||||
function py_shading(c, z)
|
||||
cmap = py_colormap(c)
|
||||
ls = pycolors.pymember("LightSource")(270,45)
|
||||
ls = pycolors["LightSource"](270,45)
|
||||
ls[:shade](z, cmap, vert_exag=0.1, blend_mode="soft")
|
||||
end
|
||||
|
||||
@@ -151,7 +161,7 @@ function py_marker(marker::Shape)
|
||||
mat[i,2] = y[i]
|
||||
end
|
||||
mat[n+1,:] = mat[1,:]
|
||||
pypath.pymember("Path")(mat)
|
||||
pypath["Path"](mat)
|
||||
end
|
||||
|
||||
const _path_MOVETO = UInt8(1)
|
||||
@@ -177,7 +187,7 @@ const _path_CLOSEPOLY = UInt8(79)
|
||||
# lastnan = nan
|
||||
# end
|
||||
# codes[n+1] = _path_CLOSEPOLY
|
||||
# pypath.pymember("Path")(mat, codes)
|
||||
# pypath["Path"](mat, codes)
|
||||
# end
|
||||
|
||||
# get the marker shape
|
||||
@@ -227,14 +237,14 @@ end
|
||||
|
||||
# # untested... return a FontProperties object from a Plots.Font
|
||||
# function py_font(font::Font)
|
||||
# pyfont.pymember("FontProperties")(
|
||||
# pyfont["FontProperties"](
|
||||
# family = font.family,
|
||||
# size = font.size
|
||||
# )
|
||||
# end
|
||||
|
||||
function get_locator_and_formatter(vals::AVec)
|
||||
pyticker.pymember("FixedLocator")(1:length(vals)), pyticker.pymember("FixedFormatter")(vals)
|
||||
pyticker["FixedLocator"](1:length(vals)), pyticker["FixedFormatter"](vals)
|
||||
end
|
||||
|
||||
function add_pyfixedformatter(cbar, vals::AVec)
|
||||
@@ -256,9 +266,9 @@ function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
end
|
||||
|
||||
function py_mask_nans(z)
|
||||
# PyPlot.pywrap(pynp.ma[:masked_invalid](PyPlot.pywrap(z)))
|
||||
PyCall.pycall(pynp.ma[:masked_invalid], Any, z)
|
||||
# pynp.ma[:masked_where](pynp.isnan(z),z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -489,7 +499,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw = KW()
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
kw[:norm] = pycolors.Normalize(; extrakw...)
|
||||
kw[:norm] = pycolors["Normalize"](; extrakw...)
|
||||
end
|
||||
lz = collect(series[:line_z])
|
||||
handle = if is3d(st)
|
||||
@@ -500,7 +510,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# for i=1:n
|
||||
# segments[i] = [(_cycle(x,i), _cycle(y,i), _cycle(z,i)), (_cycle(x,i+1), _cycle(y,i+1), _cycle(z,i+1))]
|
||||
# end
|
||||
lc = pyart3d.Line3DCollection(segments; kw...)
|
||||
lc = pyart3d["Line3DCollection"](segments; kw...)
|
||||
lc[:set_array](lz)
|
||||
ax[:add_collection3d](lc, zs=z) #, zdir='y')
|
||||
lc
|
||||
@@ -512,7 +522,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# for i=1:n
|
||||
# segments[i] = [(_cycle(x,i), _cycle(y,i)), (_cycle(x,i+1), _cycle(y,i+1))]
|
||||
# end
|
||||
lc = pycollections.LineCollection(segments; kw...)
|
||||
lc = pycollections["LineCollection"](segments; kw...)
|
||||
lc[:set_array](lz)
|
||||
ax[:add_collection](lc)
|
||||
lc
|
||||
@@ -768,7 +778,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :heatmap
|
||||
x, y, z = heatmap_edges(x), heatmap_edges(y), transpose_z(series, z.surf)
|
||||
x, y, z = heatmap_edges(x, sp[:xaxis][:scale]), heatmap_edges(y, sp[:yaxis][:scale]), transpose_z(series, z.surf)
|
||||
|
||||
expand_extrema!(sp[:xaxis], x)
|
||||
expand_extrema!(sp[:yaxis], y)
|
||||
@@ -797,8 +807,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = []
|
||||
for (i,rng) in enumerate(iter_segments(x, y))
|
||||
if length(rng) > 1
|
||||
path = pypath.pymember("Path")(hcat(x[rng], y[rng]))
|
||||
patches = pypatches.pymember("PathPatch")(
|
||||
path = pypath["Path"](hcat(x[rng], y[rng]))
|
||||
patches = pypatches["PathPatch"](
|
||||
path;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
@@ -926,7 +936,7 @@ function py_compute_axis_minval(axis::Axis)
|
||||
for series in series_list(sp)
|
||||
v = series.d[axis[:letter]]
|
||||
if !isempty(v)
|
||||
minval = NaNMath.min(minval, ignorenan_minimum(abs(v)))
|
||||
minval = NaNMath.min(minval, ignorenan_minimum(abs.(v)))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -985,7 +995,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
fig[:clear]()
|
||||
dpi = plt[:dpi]
|
||||
fig[:set_size_inches](w/dpi, h/dpi, forward = true)
|
||||
fig[:set_facecolor](py_color(plt[:background_color_outside]))
|
||||
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
|
||||
fig[:set_dpi](dpi)
|
||||
|
||||
# resize the window
|
||||
@@ -1044,7 +1054,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")]()
|
||||
@@ -1056,9 +1067,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)
|
||||
@@ -1074,7 +1089,25 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
py_add_legend(plt, sp, ax)
|
||||
|
||||
# this sets the bg color inside the grid
|
||||
ax[:set_facecolor](py_color(sp[:background_color_inside]))
|
||||
ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
|
||||
|
||||
# framestyle
|
||||
if !ispolar(sp) && !is3d(sp)
|
||||
if sp[:framestyle] == :semi
|
||||
intensity = 0.5
|
||||
ax[:spines]["right"][:set_alpha](intensity)
|
||||
ax[:spines]["top"][:set_alpha](intensity)
|
||||
ax[:spines]["right"][:set_linewidth](intensity)
|
||||
ax[:spines]["top"][:set_linewidth](intensity)
|
||||
elseif sp[:framestyle] == :axes
|
||||
ax[:spines]["right"][:set_visible](false)
|
||||
ax[:spines]["top"][:set_visible](false)
|
||||
elseif sp[:framestyle] in (:grid, :none)
|
||||
for (loc, spine) in ax[:spines]
|
||||
spine[:set_visible](false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
py_drawfig(fig)
|
||||
end
|
||||
@@ -1196,7 +1229,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
|
||||
# set some legend properties
|
||||
frame = leg[:get_frame]()
|
||||
frame[:set_facecolor](py_color(sp[:background_color_legend]))
|
||||
frame[set_facecolor_sym](py_color(sp[:background_color_legend]))
|
||||
frame[:set_edgecolor](fgcolor)
|
||||
end
|
||||
end
|
||||
@@ -1220,7 +1253,8 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
|
||||
if haskey(sp.attr, :cbar_ax)
|
||||
cbw = sp.attr[:cbar_width]
|
||||
# this is the bounding box of just the colors of the colorbar (not labels)
|
||||
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox)+2mm, _cbar_width-1mm, height(sp.bbox)-4mm)
|
||||
has_toplabel = sp[:zaxis][:extrema].emax >= 1e7
|
||||
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox) + (has_toplabel ? 4mm : 2mm), _cbar_width-1mm, height(sp.bbox) - (has_toplabel ? 6mm : 4mm))
|
||||
pcts = bbox_to_pcts(cb_bbox, figw, figh)
|
||||
sp.attr[:cbar_ax][:set_position](pcts)
|
||||
end
|
||||
|
||||
+50
-2
@@ -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
|
||||
@@ -81,7 +89,7 @@ end
|
||||
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
|
||||
function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
z = offset * π
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius))
|
||||
Shape(partialcircle(z, z + 2π, n+1., radius))
|
||||
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)
|
||||
@@ -297,12 +308,33 @@ function scalefontsize(k::Symbol, factor::Number)
|
||||
f.pointsize = round(Int, factor * f.pointsize)
|
||||
default(k, f)
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes(factor::Number)
|
||||
|
||||
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
|
||||
"""
|
||||
function scalefontsizes(factor::Number)
|
||||
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
|
||||
scalefontsize(k, factor)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes()
|
||||
|
||||
Resets font sizes to initial default values.
|
||||
"""
|
||||
function scalefontsizes()
|
||||
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
|
||||
f = default(k)
|
||||
if k in keys(_initial_fontsizes)
|
||||
factor = f.pointsize / _initial_fontsizes[k]
|
||||
scalefontsize(k, 1.0/factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
"Wrap a string with font info"
|
||||
immutable PlotText
|
||||
str::AbstractString
|
||||
@@ -310,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...)
|
||||
@@ -329,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
|
||||
@@ -576,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
|
||||
@@ -631,7 +679,7 @@ immutable Formatted{T}
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"create a BezierCurve for plotting"
|
||||
type BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
+31
-4
@@ -66,8 +66,8 @@ PlotExample("Global",
|
||||
PlotExample("Images",
|
||||
"Plot an image. y-axis is set to flipped",
|
||||
[:(begin
|
||||
import Images
|
||||
img = Images.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
|
||||
import FileIO
|
||||
img = FileIO.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
|
||||
plot(img)
|
||||
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)]
|
||||
),
|
||||
|
||||
@@ -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...;
|
||||
|
||||
+52
-44
@@ -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())
|
||||
|
||||
|
||||
@@ -220,14 +232,10 @@ if is_installed("FileIO")
|
||||
FileIO.save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, readall(open(pngfn)))
|
||||
write(io, readstring(open(pngfn)))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# function html_output_format(fmt)
|
||||
# if fmt == "png"
|
||||
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
@@ -250,76 +258,76 @@ end
|
||||
|
||||
const _ijulia_output = String["text/html"]
|
||||
|
||||
function setup_ijulia()
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
@eval begin
|
||||
import IJulia
|
||||
export set_ijulia_output
|
||||
function set_ijulia_output(mimestr::AbstractString)
|
||||
# info("Setting IJulia output format to $mimestr")
|
||||
global _ijulia_output
|
||||
_ijulia_output[1] = mimestr
|
||||
end
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
global _ijulia_output
|
||||
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
|
||||
end
|
||||
using Requires
|
||||
@require IJulia begin
|
||||
if IJulia.inited
|
||||
export set_ijulia_output
|
||||
|
||||
# default text/plain passes to html... handles Interact issues
|
||||
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
|
||||
show(io, MIME("text/html"), plt)
|
||||
end
|
||||
function set_ijulia_output(mimestr::AbstractString)
|
||||
# info("Setting IJulia output format to $mimestr")
|
||||
global _ijulia_output
|
||||
_ijulia_output[1] = mimestr
|
||||
end
|
||||
@eval set_ijulia_output("text/html")
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
global _ijulia_output
|
||||
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
|
||||
end
|
||||
|
||||
# default text/plain passes to html... handles Interact issues
|
||||
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
|
||||
show(io, MIME("text/html"), plt)
|
||||
end
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
set_ijulia_output("text/html")
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Atom PlotPane
|
||||
# ---------------------------------------------------------
|
||||
@require Juno begin
|
||||
import Hiccup, Media
|
||||
|
||||
function setup_atom()
|
||||
if isatom()
|
||||
@eval import Atom, Media
|
||||
if Juno.isactive()
|
||||
Media.media(Plot, Media.Plot)
|
||||
|
||||
# default text/plain so it doesn't complain
|
||||
function Base.show{B}(io::IO, ::MIME"text/plain", plt::Plot{B})
|
||||
print(io, "Plot{$B}()")
|
||||
end
|
||||
|
||||
function Media.render(e::Atom.Editor, plt::Plot)
|
||||
Media.render(e, nothing)
|
||||
_show{B}(io::IO, m::MIME"text/plain", plt::Plot{B}) = print(io, "Plot{$B}()")
|
||||
|
||||
function Juno.render(e::Juno.Editor, plt::Plot)
|
||||
Juno.render(e, nothing)
|
||||
end
|
||||
|
||||
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
|
||||
# this is like "display"... sends an html div with the plot to the PlotPane
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot)
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
# temporarily overwrite size to be Atom.plotsize
|
||||
sz = plt[:size]
|
||||
plt[:size] = Juno.plotsize()
|
||||
Media.render(pane, Atom.div(".fill", Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||
jsize = Juno.plotsize()
|
||||
jsize[1] == 0 && (jsize[1] = 400)
|
||||
jsize[2] == 0 && (jsize[2] = 500)
|
||||
|
||||
plt[:size] = jsize
|
||||
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
|
||||
plt[:size] = sz
|
||||
end
|
||||
# special handling for PlotlyJS
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyJSBackend})
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
end
|
||||
else
|
||||
#
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot)
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
s = "PlotPane turned off. Unset ENV[\"PLOTS_USE_ATOM_PLOTPANE\"] and restart Julia to enable it."
|
||||
Media.render(pane, Atom.div(Atom.HTML(s)))
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
|
||||
# special handling for plotly... use PlotsDisplay
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
s = "PlotPane turned off. The plotly backend cannot render in the PlotPane due to javascript issues. Plotlyjs is similar to plotly and is compatible with the plot pane."
|
||||
Media.render(pane, Atom.div(Atom.HTML(s)))
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+16
-19
@@ -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
|
||||
|
||||
+6
-5
@@ -703,7 +703,7 @@ end
|
||||
|
||||
function error_coords(xorig, yorig, ebar)
|
||||
# init empty x/y, and zip errors if passed Tuple{Vector,Vector}
|
||||
x, y = Array(float_extended_type(xorig), 0), Array(Float64, 0)
|
||||
x, y = Array{float_extended_type(xorig)}(0), Array{Float64}(0)
|
||||
# for each point, create a line segment from the bottom to the top of the errorbar
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
xi = _cycle(xorig, i)
|
||||
@@ -847,6 +847,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
|
||||
@@ -970,11 +971,11 @@ abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
# -------------------------------------------------
|
||||
# Dates
|
||||
|
||||
dateformatter(dt) = string(convert(Date, dt))
|
||||
datetimeformatter(dt) = string(convert(DateTime, dt))
|
||||
dateformatter(dt) = string(Date(Dates.UTD(dt)))
|
||||
datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
|
||||
|
||||
@recipe f(::Type{Date}, dt::Date) = (dt -> convert(Int, dt), dateformatter)
|
||||
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> convert(Int, dt), datetimeformatter)
|
||||
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
|
||||
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
|
||||
|
||||
# -------------------------------------------------
|
||||
# Complex Numbers
|
||||
|
||||
@@ -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
|
||||
|
||||
+48
-6
@@ -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))
|
||||
@@ -332,11 +333,24 @@ Base.first(x::Symbol) = x
|
||||
|
||||
sortedkeys(d::Dict) = sort(collect(keys(d)))
|
||||
|
||||
|
||||
const _scale_base = Dict{Symbol, Real}(
|
||||
:log10 => 10,
|
||||
:log2 => 2,
|
||||
:ln => e,
|
||||
)
|
||||
|
||||
"create an (n+1) list of the outsides of heatmap rectangles"
|
||||
function heatmap_edges(v::AVec)
|
||||
function heatmap_edges(v::AVec, scale::Symbol = :identity)
|
||||
vmin, vmax = ignorenan_extrema(v)
|
||||
extra = 0.5 * (vmax-vmin) / (length(v)-1)
|
||||
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
|
||||
extra_min = extra_max = 0.5 * (vmax-vmin) / (length(v)-1)
|
||||
if scale in _logScales
|
||||
vmin > 0 || error("The axis values must be positive for a $scale scale")
|
||||
while vmin - extra_min <= 0
|
||||
extra_min /= _scale_base[scale]
|
||||
end
|
||||
end
|
||||
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
|
||||
end
|
||||
|
||||
|
||||
@@ -480,16 +494,44 @@ function make_fillrange_from_ribbon(kw::KW)
|
||||
y, rib = kw[:y], kw[:ribbon]
|
||||
rib = wraptuple(rib)
|
||||
rib1, rib2 = -first(rib), last(rib)
|
||||
kw[:ribbon] = nothing
|
||||
# kw[:ribbon] = nothing
|
||||
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
|
||||
(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])
|
||||
@@ -523,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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
StatPlots
|
||||
FactCheck
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
@@ -7,4 +6,3 @@ GR
|
||||
RDatasets
|
||||
VisualRegressionTests
|
||||
UnicodePlots
|
||||
Glob
|
||||
|
||||
+5
-9
@@ -15,8 +15,7 @@ end
|
||||
|
||||
using Plots
|
||||
using StatPlots
|
||||
using FactCheck
|
||||
using Glob
|
||||
using Base.Test
|
||||
|
||||
default(size=(500,300))
|
||||
|
||||
@@ -24,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.0"
|
||||
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)
|
||||
@@ -43,11 +42,8 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
|
||||
fn = "ref$idx.png"
|
||||
|
||||
# firgure out version info
|
||||
G = glob(joinpath(relpath(refdir), "*"))
|
||||
# @show refdir fn G
|
||||
slash = (@static is_windows() ? "\\" : "/")
|
||||
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
|
||||
versions = reverse(sort(versions))
|
||||
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
|
||||
|
||||
@@ -99,7 +95,7 @@ function image_comparison_facts(pkg::Symbol;
|
||||
for i in 1:length(Plots._examples)
|
||||
i in skip && continue
|
||||
if only == nothing || i in only
|
||||
@fact @eval(image_comparison_tests(Symbol(String(Symbol($pkg))[7:end]), $i, debug=$debug, sigma=$sigma, eps=$eps)) |> success --> true
|
||||
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,8 +6,8 @@ sudo apt-get -qq update
|
||||
# sudo apt-get install -y wkhtmltopdf
|
||||
|
||||
sudo apt-get install -y xfonts-75dpi xfonts-base
|
||||
wget https://downloads.wkhtmltopdf.org/0.12/0.12.2/wkhtmltox-0.12.2_linux-precise-amd64.deb
|
||||
sudo dpkg -i wkhtmltox-0.12.2_linux-precise-amd64.deb
|
||||
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
|
||||
sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb
|
||||
# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
# sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
wkhtmltoimage http://www.google.com test.png
|
||||
|
||||
+41
-42
@@ -7,35 +7,36 @@ srand(1234)
|
||||
default(show=false, reuse=true)
|
||||
img_eps = isinteractive() ? 1e-2 : 10e-2
|
||||
|
||||
facts("GR") do
|
||||
@fact gr() --> Plots.GRBackend()
|
||||
@fact backend() --> Plots.GRBackend()
|
||||
@testset "GR" begin
|
||||
ENV["GKSwstype"] = "100"
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
image_comparison_facts(:gr, eps=img_eps)
|
||||
end
|
||||
|
||||
|
||||
facts("PyPlot") do
|
||||
@fact pyplot() --> Plots.PyPlotBackend()
|
||||
@fact backend() --> Plots.PyPlotBackend()
|
||||
@testset "PyPlot" begin
|
||||
@test pyplot() == Plots.PyPlotBackend()
|
||||
@test backend() == Plots.PyPlotBackend()
|
||||
|
||||
image_comparison_facts(:pyplot, eps=img_eps)
|
||||
end
|
||||
|
||||
facts("UnicodePlots") do
|
||||
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
|
||||
@fact backend() --> Plots.UnicodePlotsBackend()
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
# lets just make sure it runs without error
|
||||
@fact isa(plot(rand(10)), Plots.Plot) --> true
|
||||
@test isa(plot(rand(10)), Plots.Plot) == true
|
||||
end
|
||||
|
||||
# The plotlyjs testimages return a connection error on travis:
|
||||
# connect: connection refused (ECONNREFUSED)
|
||||
|
||||
# facts("PlotlyJS") do
|
||||
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
|
||||
# @fact backend() --> Plots.PlotlyJSBackend()
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# if is_linux() && isinteractive()
|
||||
# image_comparison_facts(:plotlyjs,
|
||||
@@ -53,9 +54,9 @@ end
|
||||
# ERROR: LoadError: InitError: Cannot open display:
|
||||
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
|
||||
|
||||
# facts("InspectDR") do
|
||||
# @fact inspectdr() --> Plots.InspectDRBackend()
|
||||
# @fact backend() --> Plots.InspectDRBackend()
|
||||
# @testset "InspectDR" begin
|
||||
# @test inspectdr() == Plots.InspectDRBackend()
|
||||
# @test backend() == Plots.InspectDRBackend()
|
||||
#
|
||||
# image_comparison_facts(:inspectdr,
|
||||
# skip=[
|
||||
@@ -72,41 +73,41 @@ end
|
||||
# end
|
||||
|
||||
|
||||
# facts("Plotly") do
|
||||
# @fact plotly() --> Plots.PlotlyBackend()
|
||||
# @fact backend() --> Plots.PlotlyBackend()
|
||||
# @testset "Plotly" begin
|
||||
# @test plotly() == Plots.PlotlyBackend()
|
||||
# @test backend() == Plots.PlotlyBackend()
|
||||
#
|
||||
# # # until png generation is reliable on OSX, just test on linux
|
||||
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# facts("Immerse") do
|
||||
# @fact immerse() --> Plots.ImmerseBackend()
|
||||
# @fact backend() --> Plots.ImmerseBackend()
|
||||
# @testset "Immerse" begin
|
||||
# @test immerse() == Plots.ImmerseBackend()
|
||||
# @test backend() == Plots.ImmerseBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Gadfly
|
||||
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# facts("PlotlyJS") do
|
||||
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
|
||||
# @fact backend() --> Plots.PlotlyJSBackend()
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Plotly
|
||||
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# facts("Gadfly") do
|
||||
# @fact gadfly() --> Plots.GadflyBackend()
|
||||
# @fact backend() --> Plots.GadflyBackend()
|
||||
# @testset "Gadfly" begin
|
||||
# @test gadfly() == Plots.GadflyBackend()
|
||||
# @test backend() == Plots.GadflyBackend()
|
||||
#
|
||||
# @fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
|
||||
# @fact plot(Int[1,2,3], rand(3)) --> not(nothing)
|
||||
# @fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
|
||||
# @fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
|
||||
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
|
||||
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
|
||||
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
|
||||
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
|
||||
#
|
||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
|
||||
# end
|
||||
@@ -114,24 +115,24 @@ end
|
||||
|
||||
|
||||
|
||||
facts("Axes") do
|
||||
@testset "Axes" begin
|
||||
p = plot()
|
||||
axis = p.subplots[1][:xaxis]
|
||||
@fact typeof(axis) --> Plots.Axis
|
||||
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
|
||||
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
|
||||
@fact Plots.ignorenan_extrema(axis) --> (0.5,1.5)
|
||||
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
@test typeof(axis) == Plots.Axis
|
||||
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
|
||||
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5,1.5)
|
||||
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
|
||||
Plots.discrete_value!(axis, ["x$i" for i=1:5])
|
||||
Plots.discrete_value!(axis, ["x$i" for i=0:2])
|
||||
@fact Plots.ignorenan_extrema(axis) --> (0.5, 7.5)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
|
||||
end
|
||||
|
||||
|
||||
# tests for preprocessing recipes
|
||||
|
||||
# facts("recipes") do
|
||||
# @testset "recipes" begin
|
||||
|
||||
# user recipe
|
||||
|
||||
@@ -168,6 +169,4 @@ end
|
||||
# end
|
||||
|
||||
|
||||
|
||||
FactCheck.exitstatus()
|
||||
end # module
|
||||
|
||||
Reference in New Issue
Block a user