Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9c9fc615b | |||
| 50c62ec48e | |||
| b16ced0367 |
@@ -5,4 +5,3 @@
|
||||
examples/.ipynb_checkpoints/*
|
||||
examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-latest.min.js
|
||||
deps/build.log
|
||||
|
||||
+8
-9
@@ -4,11 +4,10 @@ os:
|
||||
- linux
|
||||
# - osx
|
||||
julia:
|
||||
# - 0.7
|
||||
- nightly
|
||||
# matrix:
|
||||
# allow_failures:
|
||||
# - julia: nightly
|
||||
- 0.7
|
||||
matrix:
|
||||
allow_failures:
|
||||
- julia: nightly
|
||||
|
||||
# # before install:
|
||||
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
@@ -43,10 +42,10 @@ before_install:
|
||||
notifications:
|
||||
email: true
|
||||
# uncomment the following lines to override the default test script
|
||||
# script:
|
||||
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
# - julia -e 'import Pkg; Pkg.add(Pkg.PackageSpec(path=pwd())); Pkg.build("Plots")'
|
||||
# - julia test/travis_commands.jl
|
||||
script:
|
||||
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
- julia -e 'using Pkg; Pkg.add(pwd()); Pkg.build("Plots")'
|
||||
- julia test/travis_commands.jl
|
||||
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
|
||||
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
|
||||
|
||||
@@ -10,44 +10,7 @@
|
||||
|
||||
---
|
||||
## (current master)
|
||||
- All new development should target Julia 1.x!
|
||||
|
||||
## 0.20.0
|
||||
Many updates, min julia 1.0
|
||||
- change display type to use PlotsDisplay (fixes Juno integration)
|
||||
- change all internal uses of `d` to `plotattributes` (no user change)
|
||||
- change spy implementation to use `scatter` not `heatmap`
|
||||
- sort x axes when passing a vector of strings as x
|
||||
- improve performance of marker_z
|
||||
- update CI to 1.0
|
||||
- minor depwarn ifixes
|
||||
- only draw one colorbar with GR
|
||||
- add colorbar_title to GR and pgfplots
|
||||
- fix savefig with latexstrings for PyPlot
|
||||
- fix NamedTuple integration
|
||||
- don't export `P2` and `P3`
|
||||
- make it possible to use 2-argument function as argument to marker_z
|
||||
- make `plotattr` work again
|
||||
|
||||
## 0.19.3
|
||||
- fix some julia 0.7 deprecations
|
||||
- fix 32-bit OS functionality
|
||||
|
||||
## 0.19.2
|
||||
- several small fixes for 1.0 compatibility
|
||||
|
||||
## 0.19.1
|
||||
- don't broadcast plot_color
|
||||
|
||||
## 0.19.0
|
||||
- Refactor conditional loading to use Requires
|
||||
- Many fixes for 1.0 compatibility
|
||||
|
||||
## 0.18.0
|
||||
- update minor version to 0.7
|
||||
|
||||
## 0.17.4
|
||||
- fix thickness_scaling for pyplot
|
||||
- All new development should target Julia 0.7!
|
||||
|
||||
## 0.17.3
|
||||
- Log-scale heatmap edge computation
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[](https://travis-ci.org/JuliaPlots/Plots.jl)
|
||||
[](https://ci.appveyor.com/project/mkborregaard/plots-jl)
|
||||
[](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<a href="http://docs.juliaplots.org/latest/" target="_blank"><img src="https://img.shields.io/badge/docs-latest-blue.svg" alt="Latest documentation"></a>
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
|
||||
<!-- [](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
|
||||
@@ -22,3 +21,5 @@ Plots is a plotting API and toolset. My goals with the package are:
|
||||
- **Consistent**. Don't commit to one graphics package, use the same code everywhere.
|
||||
- **Lightweight**. Very few dependencies.
|
||||
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
|
||||
|
||||
View the [full documentation](http://docs.juliaplots.org/latest).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
julia 1.0
|
||||
julia 0.7-alpha
|
||||
|
||||
RecipesBase 0.6.0
|
||||
RecipesBase 0.2.3
|
||||
PlotUtils 0.4.1
|
||||
PlotThemes 0.1.3
|
||||
Reexport
|
||||
|
||||
+10
-12
@@ -1,14 +1,15 @@
|
||||
environment:
|
||||
matrix:
|
||||
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
|
||||
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-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://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"
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
@@ -31,11 +32,8 @@ install:
|
||||
build_script:
|
||||
# Need to convert from shallow to complete for Pkg.clone to work
|
||||
- IF EXIST .git\shallow (git fetch --unshallow)
|
||||
- C:\projects\julia\bin\julia -e "
|
||||
using InteractiveUtils, Pkg;
|
||||
versioninfo();
|
||||
Pkg.clone(pwd(), \"Plots\");
|
||||
Pkg.build(\"Plots\")"
|
||||
- C:\projects\julia\bin\julia -e "versioninfo(); Pkg.clone(pwd(), \"Plots\"); Pkg.build(\"Plots\")"
|
||||
|
||||
test_script:
|
||||
- C:\projects\julia\bin\julia -e "using Pkg; Pkg.test(\"Plots\")"
|
||||
# - C:\projects\julia\bin\julia -e "Pkg.test(\"Plots\")"
|
||||
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"
|
||||
|
||||
+23
-7
@@ -1,3 +1,5 @@
|
||||
__precompile__(true)
|
||||
|
||||
module Plots
|
||||
|
||||
using Reexport
|
||||
@@ -5,7 +7,6 @@ using Reexport
|
||||
import StaticArrays
|
||||
using StaticArrays.FixedSizeArrays
|
||||
using Dates, Printf, Statistics, Base64, LinearAlgebra
|
||||
import SparseArrays: findnz
|
||||
|
||||
@reexport using RecipesBase
|
||||
import RecipesBase: plot, plot!, animate
|
||||
@@ -104,6 +105,8 @@ export
|
||||
rotate,
|
||||
rotate!,
|
||||
center,
|
||||
P2,
|
||||
P3,
|
||||
BezierCurve,
|
||||
|
||||
plotattr
|
||||
@@ -116,7 +119,7 @@ ignorenan_minimum(x) = Base.minimum(x)
|
||||
ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
|
||||
ignorenan_maximum(x) = Base.maximum(x)
|
||||
ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
|
||||
ignorenan_mean(x) = Statistics.mean(x)
|
||||
ignorenan_mean(x) = Base.mean(x)
|
||||
ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
|
||||
ignorenan_extrema(x) = Base.extrema(x)
|
||||
|
||||
@@ -168,7 +171,6 @@ include("arg_desc.jl")
|
||||
include("plotattr.jl")
|
||||
include("backends.jl")
|
||||
include("output.jl")
|
||||
include("init.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -234,10 +236,10 @@ zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmi
|
||||
|
||||
|
||||
"Set xticks for an existing plot"
|
||||
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
|
||||
xticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
|
||||
|
||||
"Set yticks for an existing plot"
|
||||
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
|
||||
yticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
|
||||
|
||||
xticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
|
||||
@@ -272,8 +274,8 @@ let PlotOrSubplot = Union{Plot, Subplot}
|
||||
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
|
||||
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
|
||||
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
|
||||
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
|
||||
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
|
||||
global xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
|
||||
global yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
|
||||
global xticks!(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
|
||||
global yticks!(plt::PlotOrSubplot,
|
||||
@@ -293,4 +295,18 @@ end
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
# for compatibility with Requires.jl:
|
||||
@init begin
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
if haskey(Main.PLOTS_DEFAULTS, :theme)
|
||||
theme(Main.PLOTS_DEFAULTS[:theme])
|
||||
end
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
k == :theme || default(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
end # module
|
||||
|
||||
+3
-3
@@ -87,7 +87,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString,
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
|
||||
end
|
||||
|
||||
show_msg && @info("Saved animation to ", fn)
|
||||
show_msg && info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
end
|
||||
|
||||
@@ -142,7 +142,7 @@ function _animate(forloop::Expr, args...; callgif = false)
|
||||
end
|
||||
|
||||
push!(block.args, :(if $filterexpr; frame($animsym); end))
|
||||
push!(block.args, :(global $countersym += 1))
|
||||
push!(block.args, :($countersym += 1))
|
||||
|
||||
# add a final call to `gif(anim)`?
|
||||
retval = callgif ? :(gif($animsym)) : animsym
|
||||
@@ -151,7 +151,7 @@ function _animate(forloop::Expr, args...; callgif = false)
|
||||
esc(quote
|
||||
$freqassert # if filtering, check frequency is an Integer > 0
|
||||
$animsym = Animation() # init animation object
|
||||
global $countersym = 1 # init iteration counter
|
||||
$countersym = 1 # init iteration counter
|
||||
$forloop # for loop, saving a frame after each iteration
|
||||
$retval # return the animation object, or the gif
|
||||
end)
|
||||
|
||||
+3
-9
@@ -21,14 +21,14 @@ const _arg_desc = KW(
|
||||
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
|
||||
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
|
||||
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(min(x), stop = extrema(x), length = 25)`",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
|
||||
:smooth => "Bool. Add a regression line?",
|
||||
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
|
||||
:x => "Various. Input data. First Dimension",
|
||||
:y => "Various. Input data. Second Dimension",
|
||||
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
|
||||
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
|
||||
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
|
||||
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
|
||||
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
|
||||
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
|
||||
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
|
||||
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
|
||||
@@ -139,12 +139,6 @@ const _arg_desc = KW(
|
||||
: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)",
|
||||
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
|
||||
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
|
||||
:minorticks => "Integer. Intervals to divide the gap between major ticks into",
|
||||
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
|
||||
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
|
||||
:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)",
|
||||
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
|
||||
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
|
||||
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
|
||||
|
||||
+266
-326
File diff suppressed because it is too large
Load Diff
+56
-131
@@ -8,7 +8,7 @@
|
||||
|
||||
function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
# init with values from _plot_defaults
|
||||
plotattributes = KW(
|
||||
d = KW(
|
||||
:letter => letter,
|
||||
# :extrema => (Inf, -Inf),
|
||||
:extrema => Extrema(),
|
||||
@@ -22,14 +22,14 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
for (k,v) in _axis_defaults
|
||||
lk = Symbol(letter, k)
|
||||
lv = _axis_defaults_byletter[lk]
|
||||
plotattributes[k] = (lv == :match ? v : lv)
|
||||
d[k] = (lv == :match ? v : lv)
|
||||
end
|
||||
|
||||
# merge!(plotattributes, _axis_defaults)
|
||||
plotattributes[:discrete_values] = []
|
||||
# merge!(d, _axis_defaults)
|
||||
d[:discrete_values] = []
|
||||
|
||||
# update the defaults
|
||||
attr!(Axis([sp], plotattributes), args...; kw...)
|
||||
attr!(Axis([sp], d), args...; kw...)
|
||||
end
|
||||
|
||||
function get_axis(sp::Subplot, letter::Symbol)
|
||||
@@ -41,46 +41,46 @@ function get_axis(sp::Subplot, letter::Symbol)
|
||||
end::Axis
|
||||
end
|
||||
|
||||
function process_axis_arg!(plotattributes::KW, arg, letter = "")
|
||||
function process_axis_arg!(d::KW, arg, letter = "")
|
||||
T = typeof(arg)
|
||||
arg = get(_scaleAliases, arg, arg)
|
||||
|
||||
if typeof(arg) <: Font
|
||||
plotattributes[Symbol(letter,:tickfont)] = arg
|
||||
plotattributes[Symbol(letter,:guidefont)] = arg
|
||||
d[Symbol(letter,:tickfont)] = arg
|
||||
d[Symbol(letter,:guidefont)] = arg
|
||||
|
||||
elseif arg in _allScales
|
||||
plotattributes[Symbol(letter,:scale)] = arg
|
||||
d[Symbol(letter,:scale)] = arg
|
||||
|
||||
elseif arg in (:flip, :invert, :inverted)
|
||||
plotattributes[Symbol(letter,:flip)] = true
|
||||
d[Symbol(letter,:flip)] = true
|
||||
|
||||
elseif T <: AbstractString
|
||||
plotattributes[Symbol(letter,:guide)] = arg
|
||||
d[Symbol(letter,:guide)] = arg
|
||||
|
||||
# xlims/ylims
|
||||
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
|
||||
sym = typeof(arg[1]) <: Number ? :lims : :ticks
|
||||
plotattributes[Symbol(letter,sym)] = arg
|
||||
d[Symbol(letter,sym)] = arg
|
||||
|
||||
# xticks/yticks
|
||||
elseif T <: AVec
|
||||
plotattributes[Symbol(letter,:ticks)] = arg
|
||||
d[Symbol(letter,:ticks)] = arg
|
||||
|
||||
elseif arg == nothing
|
||||
plotattributes[Symbol(letter,:ticks)] = []
|
||||
d[Symbol(letter,:ticks)] = []
|
||||
|
||||
elseif T <: Bool || arg in _allShowaxisArgs
|
||||
plotattributes[Symbol(letter,:showaxis)] = showaxis(arg, letter)
|
||||
d[Symbol(letter,:showaxis)] = showaxis(arg, letter)
|
||||
|
||||
elseif typeof(arg) <: Number
|
||||
plotattributes[Symbol(letter,:rotation)] = arg
|
||||
d[Symbol(letter,:rotation)] = arg
|
||||
|
||||
elseif typeof(arg) <: Function
|
||||
plotattributes[Symbol(letter,:formatter)] = arg
|
||||
d[Symbol(letter,:formatter)] = arg
|
||||
|
||||
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis))
|
||||
@warn("Skipped $(letter)axis arg $arg")
|
||||
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_axis))
|
||||
warn("Skipped $(letter)axis arg $arg")
|
||||
|
||||
end
|
||||
end
|
||||
@@ -88,28 +88,28 @@ end
|
||||
# update an Axis object with magic args and keywords
|
||||
function attr!(axis::Axis, args...; kw...)
|
||||
# first process args
|
||||
plotattributes = axis.plotattributes
|
||||
d = axis.d
|
||||
for arg in args
|
||||
process_axis_arg!(plotattributes, arg)
|
||||
process_axis_arg!(d, arg)
|
||||
end
|
||||
|
||||
# then override for any keywords... only those keywords that already exists in plotattributes
|
||||
# then override for any keywords... only those keywords that already exists in d
|
||||
for (k,v) in kw
|
||||
if haskey(plotattributes, k)
|
||||
if haskey(d, k)
|
||||
if k == :discrete_values
|
||||
# add these discrete values to the axis
|
||||
for vi in v
|
||||
discrete_value!(axis, vi)
|
||||
end
|
||||
else
|
||||
plotattributes[k] = v
|
||||
d[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# replace scale aliases
|
||||
if haskey(_scaleAliases, plotattributes[:scale])
|
||||
plotattributes[:scale] = _scaleAliases[plotattributes[:scale]]
|
||||
if haskey(_scaleAliases, d[:scale])
|
||||
d[:scale] = _scaleAliases[d[:scale]]
|
||||
end
|
||||
|
||||
axis
|
||||
@@ -117,10 +117,10 @@ end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
Base.show(io::IO, axis::Axis) = dumpdict(axis.plotattributes, "Axis", true)
|
||||
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.plotattributes, k)
|
||||
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v, ks...)
|
||||
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k)
|
||||
Base.show(io::IO, axis::Axis) = dumpdict(axis.d, "Axis", true)
|
||||
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.d, k)
|
||||
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.d, v, ks...)
|
||||
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.d, k)
|
||||
ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
|
||||
|
||||
|
||||
@@ -286,34 +286,6 @@ _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])
|
||||
|
||||
function get_minor_ticks(axis,ticks)
|
||||
axis[:minorticks] in (nothing, false) && !axis[:minorgrid] && return nothing
|
||||
ticks = ticks[1]
|
||||
length(ticks) < 2 && return nothing
|
||||
|
||||
amin, amax = axis_limits(axis)
|
||||
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
|
||||
if length(ticks) > 2
|
||||
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
|
||||
elseif axis[:scale] == :none
|
||||
ratio = 1
|
||||
else
|
||||
return nothing
|
||||
end
|
||||
first_step = ticks[2] - ticks[1]
|
||||
last_step = ticks[end] - ticks[end-1]
|
||||
ticks = [ticks[1] - first_step/ratio; ticks; ticks[end] + last_step*ratio]
|
||||
|
||||
#Default to 5 intervals between major ticks
|
||||
n = typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : 5
|
||||
minorticks = typeof(ticks[1])[]
|
||||
for (i,hi) in enumerate(ticks[2:end])
|
||||
lo = ticks[i]
|
||||
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
|
||||
end
|
||||
minorticks[amin .<= minorticks .<= amax]
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -322,7 +294,7 @@ function reset_extrema!(sp::Subplot)
|
||||
sp[Symbol(asym,:axis)][:extrema] = Extrema()
|
||||
end
|
||||
for series in sp.series_list
|
||||
expand_extrema!(sp, series.plotattributes)
|
||||
expand_extrema!(sp, series.d)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -357,17 +329,17 @@ function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
|
||||
end
|
||||
|
||||
|
||||
function expand_extrema!(sp::Subplot, plotattributes::KW)
|
||||
vert = isvertical(plotattributes)
|
||||
function expand_extrema!(sp::Subplot, d::KW)
|
||||
vert = isvertical(d)
|
||||
|
||||
# first expand for the data
|
||||
for letter in (:x, :y, :z)
|
||||
data = plotattributes[if vert
|
||||
data = d[if vert
|
||||
letter
|
||||
else
|
||||
letter == :x ? :y : letter == :y ? :x : :z
|
||||
end]
|
||||
if letter != :z && plotattributes[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
|
||||
if letter != :z && d[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
|
||||
data = [NaN]
|
||||
end
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
@@ -379,30 +351,30 @@ function expand_extrema!(sp::Subplot, plotattributes::KW)
|
||||
elseif eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf))
|
||||
if !(eltype(data) <: Number)
|
||||
# huh... must have been a mis-typed surface? lets swap it out
|
||||
data = plotattributes[letter] = Surface(Matrix{Float64}(data.surf))
|
||||
data = d[letter] = Surface(Matrix{Float64}(data.surf))
|
||||
end
|
||||
expand_extrema!(axis, data)
|
||||
elseif data != nothing
|
||||
# TODO: need more here... gotta track the discrete reference value
|
||||
# as well as any coord offset (think of boxplot shape coords... they all
|
||||
# correspond to the same x-value)
|
||||
plotattributes[letter], plotattributes[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
|
||||
expand_extrema!(axis, plotattributes[letter])
|
||||
d[letter], d[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
|
||||
expand_extrema!(axis, d[letter])
|
||||
end
|
||||
end
|
||||
|
||||
# # expand for fillrange/bar_width
|
||||
# fillaxis, baraxis = sp.attr[:yaxis], sp.attr[:xaxis]
|
||||
# if isvertical(plotattributes)
|
||||
# if isvertical(d)
|
||||
# fillaxis, baraxis = baraxis, fillaxis
|
||||
# end
|
||||
|
||||
# expand for fillrange
|
||||
fr = plotattributes[:fillrange]
|
||||
if fr == nothing && plotattributes[:seriestype] == :bar
|
||||
fr = d[:fillrange]
|
||||
if fr == nothing && d[:seriestype] == :bar
|
||||
fr = 0.0
|
||||
end
|
||||
if fr != nothing && !all3D(plotattributes)
|
||||
if fr != nothing && !all3D(d)
|
||||
axis = sp.attr[vert ? :yaxis : :xaxis]
|
||||
if typeof(fr) <: Tuple
|
||||
for fri in fr
|
||||
@@ -414,13 +386,13 @@ function expand_extrema!(sp::Subplot, plotattributes::KW)
|
||||
end
|
||||
|
||||
# expand for bar_width
|
||||
if plotattributes[:seriestype] == :bar
|
||||
if d[:seriestype] == :bar
|
||||
dsym = vert ? :x : :y
|
||||
data = plotattributes[dsym]
|
||||
data = d[dsym]
|
||||
|
||||
bw = plotattributes[:bar_width]
|
||||
bw = d[:bar_width]
|
||||
if bw == nothing
|
||||
bw = plotattributes[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
|
||||
bw = d[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
|
||||
end
|
||||
axis = sp.attr[Symbol(dsym, :axis)]
|
||||
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
|
||||
@@ -428,11 +400,11 @@ function expand_extrema!(sp::Subplot, plotattributes::KW)
|
||||
end
|
||||
|
||||
# expand for heatmaps
|
||||
if plotattributes[:seriestype] == :heatmap
|
||||
if d[:seriestype] == :heatmap
|
||||
for letter in (:x, :y)
|
||||
data = plotattributes[letter]
|
||||
data = d[letter]
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
scale = get(plotattributes, Symbol(letter, "scale"), :identity)
|
||||
scale = get(d, Symbol(letter, "scale"), :identity)
|
||||
expand_extrema!(axis, heatmap_edges(data, scale))
|
||||
end
|
||||
end
|
||||
@@ -462,7 +434,7 @@ function default_should_widen(axis::Axis)
|
||||
if !is_2tuple(axis[:lims])
|
||||
for sp in axis.sps
|
||||
for series in series_list(sp)
|
||||
if series.plotattributes[:seriestype] in _widen_seriestypes
|
||||
if series.d[:seriestype] in _widen_seriestypes
|
||||
should_widen = true
|
||||
end
|
||||
end
|
||||
@@ -572,12 +544,12 @@ end
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
function pie_labels(sp::Subplot, series::Series)
|
||||
plotattributes = series.plotattributes
|
||||
if haskey(plotattributes,:x_discrete_indices)
|
||||
dvals = sp.attr[:xaxis].plotattributes[:discrete_values]
|
||||
[dvals[idx] for idx in plotattributes[:x_discrete_indices]]
|
||||
d = series.d
|
||||
if haskey(d,:x_discrete_indices)
|
||||
dvals = sp.attr[:xaxis].d[:discrete_values]
|
||||
[dvals[idx] for idx in d[:x_discrete_indices]]
|
||||
else
|
||||
plotattributes[:x]
|
||||
d[:x]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -590,16 +562,12 @@ function axis_drawing_info(sp::Subplot)
|
||||
ymin, ymax = axis_limits(yaxis)
|
||||
xticks = get_ticks(xaxis)
|
||||
yticks = get_ticks(yaxis)
|
||||
xminorticks = get_minor_ticks(xaxis,xticks)
|
||||
yminorticks = get_minor_ticks(yaxis,yticks)
|
||||
xaxis_segs = Segments(2)
|
||||
yaxis_segs = Segments(2)
|
||||
xtick_segs = Segments(2)
|
||||
ytick_segs = Segments(2)
|
||||
xgrid_segs = Segments(2)
|
||||
ygrid_segs = Segments(2)
|
||||
xminorgrid_segs = Segments(2)
|
||||
yminorgrid_segs = Segments(2)
|
||||
xborder_segs = Segments(2)
|
||||
yborder_segs = Segments(2)
|
||||
|
||||
@@ -642,28 +610,6 @@ function axis_drawing_info(sp::Subplot)
|
||||
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
|
||||
end
|
||||
end
|
||||
if !(xaxis[:minorticks] in (nothing, false)) || xaxis[:minorgrid]
|
||||
f = scalefunc(yaxis[:scale])
|
||||
invf = invscalefunc(yaxis[:scale])
|
||||
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
|
||||
t1 = invf(f(ymin) + 0.01 * (f(ymax) - f(ymin)) * ticks_in)
|
||||
t2 = invf(f(ymax) - 0.01 * (f(ymax) - f(ymin)) * ticks_in)
|
||||
t3 = invf(f(0) + 0.01 * (f(ymax) - f(ymin)) * ticks_in)
|
||||
|
||||
for xminortick in xminorticks
|
||||
if xaxis[:showaxis]
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
(0, t3)
|
||||
else
|
||||
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
|
||||
end
|
||||
push!(xtick_segs, (xminortick, tick_start), (xminortick, tick_stop)) # bottom tick
|
||||
end
|
||||
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
|
||||
xaxis[:minorgrid] && push!(xminorgrid_segs, (xminortick, ymin), (xminortick, ymax)) # vertical grid
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# yaxis
|
||||
if yaxis[:showaxis]
|
||||
@@ -703,28 +649,7 @@ function axis_drawing_info(sp::Subplot)
|
||||
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
|
||||
end
|
||||
end
|
||||
if !(yaxis[:minorticks] in (nothing, false)) || yaxis[:minorgrid]
|
||||
f = scalefunc(xaxis[:scale])
|
||||
invf = invscalefunc(xaxis[:scale])
|
||||
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
|
||||
t1 = invf(f(xmin) + 0.01 * (f(xmax) - f(xmin)) * ticks_in)
|
||||
t2 = invf(f(xmax) - 0.01 * (f(xmax) - f(xmin)) * ticks_in)
|
||||
t3 = invf(f(0) + 0.01 * (f(xmax) - f(xmin)) * ticks_in)
|
||||
|
||||
for ytick in yminorticks
|
||||
if yaxis[:showaxis]
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
(0, t3)
|
||||
else
|
||||
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
|
||||
end
|
||||
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
|
||||
end
|
||||
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
|
||||
yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs
|
||||
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs
|
||||
end
|
||||
|
||||
+43
-153
@@ -6,8 +6,6 @@ const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
|
||||
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
|
||||
const _backends = Symbol[]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
const _default_backends = (:none, :gr, :plotly)
|
||||
const _backendPackage = Dict{Symbol, Symbol}()
|
||||
|
||||
"Returns a list of supported backends"
|
||||
backends() = _backends
|
||||
@@ -15,12 +13,9 @@ 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")
|
||||
backend_package(pkg::Symbol) = pkg in _default_backends ? :Plots : Symbol("Plots", _backendPackage[pkg])
|
||||
backend_package_name(sym::Symbol) = sym in _default_backends ? :Plots : _backendPackage[sym]
|
||||
|
||||
macro init_backend(s)
|
||||
package_str = string(s)
|
||||
str = lowercase(package_str)
|
||||
str = lowercase(string(s))
|
||||
sym = Symbol(str)
|
||||
T = Symbol(string(s) * "Backend")
|
||||
esc(quote
|
||||
@@ -28,25 +23,24 @@ macro init_backend(s)
|
||||
export $sym
|
||||
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
|
||||
backend_name(::$T) = Symbol($str)
|
||||
backend_package_name(pkg::$T) = backend_package_name(Symbol($str))
|
||||
push!(_backends, Symbol($str))
|
||||
_backendType[Symbol($str)] = $T
|
||||
_backendSymbol[$T] = Symbol($str)
|
||||
_backendPackage[Symbol($str)] = Symbol($package_str)
|
||||
# include("backends/" * $str * ".jl")
|
||||
include("backends/" * $str * ".jl")
|
||||
end)
|
||||
end
|
||||
|
||||
# include("backends/web.jl")
|
||||
include("backends/web.jl")
|
||||
# include("backends/supported.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function add_backend(pkg::Symbol)
|
||||
@info("To do a standard install of $pkg, copy and run this:\n\n")
|
||||
info("To do a standard install of $pkg, copy and run this:\n\n")
|
||||
println(add_backend_string(_backend_instance(pkg)))
|
||||
println()
|
||||
end
|
||||
add_backend_string(b::AbstractBackend) = warn("No custom install defined for $(backend_name(b))")
|
||||
|
||||
# don't do anything as a default
|
||||
_create_backend_figure(plt::Plot) = nothing
|
||||
@@ -141,30 +135,30 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
function pickDefaultBackend()
|
||||
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
|
||||
if env_default != ""
|
||||
sym = Symbol(lowercase(env_default))
|
||||
if sym in _backends
|
||||
if sym in _initialized_backends
|
||||
if env_default in keys(Pkg.installed())
|
||||
sym = Symbol(lowercase(env_default))
|
||||
if haskey(_backendType, sym)
|
||||
return backend(sym)
|
||||
else
|
||||
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
|
||||
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
|
||||
join(sort(_backends), "\n\t"))
|
||||
end
|
||||
else
|
||||
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
|
||||
join(sort(_backends), "\n\t"))
|
||||
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not installed.")
|
||||
end
|
||||
end
|
||||
|
||||
# the ordering/inclusion of this package list is my semi-arbitrary guess at
|
||||
# which one someone will want to use if they have the package installed...accounting for
|
||||
# features, speed, and robustness
|
||||
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
|
||||
# if pkgstr in keys(Pkg.installed())
|
||||
# return backend(Symbol(lowercase(pkgstr)))
|
||||
# end
|
||||
# end
|
||||
for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
|
||||
if pkgstr in keys(Pkg.installed())
|
||||
return backend(Symbol(lowercase(pkgstr)))
|
||||
end
|
||||
end
|
||||
|
||||
# the default if nothing else is installed
|
||||
backend(:gr)
|
||||
backend(:plotly)
|
||||
end
|
||||
|
||||
|
||||
@@ -180,6 +174,24 @@ function backend()
|
||||
pickDefaultBackend()
|
||||
end
|
||||
|
||||
sym = CURRENT_BACKEND.sym
|
||||
if !(sym in _initialized_backends)
|
||||
|
||||
# # initialize
|
||||
# println("[Plots.jl] Initializing backend: ", sym)
|
||||
|
||||
inst = _backend_instance(sym)
|
||||
try
|
||||
_initialize_backend(inst)
|
||||
catch err
|
||||
warn("Couldn't initialize $sym. (might need to install it?)")
|
||||
add_backend(sym)
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
push!(_initialized_backends, sym)
|
||||
|
||||
end
|
||||
CURRENT_BACKEND.pkg
|
||||
end
|
||||
|
||||
@@ -187,29 +199,16 @@ end
|
||||
Set the plot backend.
|
||||
"""
|
||||
function backend(pkg::AbstractBackend)
|
||||
sym = backend_name(pkg)
|
||||
if sym in _initialized_backends
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
else
|
||||
# try
|
||||
_initialize_backend(pkg)
|
||||
push!(_initialized_backends, sym)
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
# catch
|
||||
# add_backend(sym)
|
||||
# end
|
||||
end
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
warn_on_deprecated_backend(CURRENT_BACKEND.sym)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
backend()
|
||||
end
|
||||
|
||||
function backend(sym::Symbol)
|
||||
if sym in _backends
|
||||
backend(_backend_instance(sym))
|
||||
else
|
||||
@warn("`:$sym` is not a supported backend.")
|
||||
end
|
||||
function backend(modname::Symbol)
|
||||
warn_on_deprecated_backend(modname)
|
||||
CURRENT_BACKEND.sym = modname
|
||||
CURRENT_BACKEND.pkg = _backend_instance(modname)
|
||||
backend()
|
||||
end
|
||||
|
||||
@@ -217,7 +216,7 @@ const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
|
||||
|
||||
function warn_on_deprecated_backend(bsym::Symbol)
|
||||
if bsym in _deprecated_backends
|
||||
@warn("Backend $bsym has been deprecated. It may not work as originally intended.")
|
||||
warn("Backend $bsym has been deprecated. It may not work as originally intended.")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -309,112 +308,3 @@ end
|
||||
|
||||
# is_subplot_supported(::AbstractBackend) = false
|
||||
# is_subplot_supported() = is_subplot_supported(backend())
|
||||
|
||||
|
||||
################################################################################
|
||||
# initialize the backends
|
||||
|
||||
function _initialize_backend(pkg::AbstractBackend)
|
||||
sym = backend_package_name(pkg)
|
||||
@eval Main begin
|
||||
import $sym
|
||||
export $sym
|
||||
end
|
||||
end
|
||||
|
||||
function add_backend_string(pkg::AbstractBackend)
|
||||
sym = backend_package_name(pkg)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("$sym")
|
||||
"""
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# glvisualize
|
||||
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval Main begin
|
||||
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
|
||||
import FileIO, Images
|
||||
export GLVisualize
|
||||
import Reactive: Signal
|
||||
import GLAbstraction: Style
|
||||
import GLVisualize: visualize
|
||||
import Plots.GL
|
||||
import UnicodeFun
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# hdf5
|
||||
|
||||
function _initialize_backend(::HDF5Backend)
|
||||
@eval Main begin
|
||||
import HDF5
|
||||
export HDF5
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# PGFPLOTS
|
||||
|
||||
function add_backend_string(::PGFPlotsBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("PGFPlots")
|
||||
Pkg.build("PGFPlots")
|
||||
"""
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# plotlyjs
|
||||
|
||||
function add_backend_string(::PlotlyJSBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("PlotlyJS")
|
||||
Pkg.add("Rsvg")
|
||||
import Blink
|
||||
Blink.AtomShell.install()
|
||||
"""
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pyplot
|
||||
|
||||
function _initialize_backend(::PyPlotBackend)
|
||||
@eval Main begin
|
||||
import PyPlot, PyCall
|
||||
import LaTeXStrings
|
||||
|
||||
export PyPlot
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
end
|
||||
end
|
||||
|
||||
function add_backend_string(::PyPlotBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.add("PyCall")
|
||||
Pkg.add("LaTeXStrings")
|
||||
withenv("PYTHON" => "") do
|
||||
Pkg.build("PyCall")
|
||||
Pkg.build("PyPlot")
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# unicodeplots
|
||||
function add_backend_string(::UnicodePlotsBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.build("UnicodePlots")
|
||||
"""
|
||||
end
|
||||
|
||||
+198
-177
@@ -9,6 +9,10 @@ TODO
|
||||
* fix units in all visuals (e.g dotted lines, marker scale, surfaces)
|
||||
=#
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "glvisualize.jl"))
|
||||
end
|
||||
|
||||
const _glvisualize_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
@@ -57,11 +61,36 @@ const _glvisualize_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _glvisualize_marker = _allMarkers
|
||||
const _glvisualize_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
|
||||
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
|
||||
is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
|
||||
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
|
||||
GL = Plots
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval begin
|
||||
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
|
||||
import FileIO, Images
|
||||
export GLVisualize
|
||||
import Reactive: Signal
|
||||
import GLAbstraction: Style
|
||||
import GLVisualize: visualize
|
||||
import Plots.GL
|
||||
import UnicodeFun
|
||||
Plots.slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
|
||||
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
|
||||
is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
|
||||
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
|
||||
GL = Plots
|
||||
end
|
||||
end
|
||||
|
||||
function add_backend_string(b::GLVisualizeBackend)
|
||||
"""
|
||||
if !Plots.is_installed("GLVisualize")
|
||||
Pkg.add("GLVisualize")
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -182,7 +211,7 @@ function gl_marker(shape::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
function extract_limits(sp, plotattributes, kw_args)
|
||||
function extract_limits(sp, d, kw_args)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
if isfinite(clims[1]) && isfinite(clims[2])
|
||||
@@ -200,70 +229,70 @@ to_vec(::Type{T}, vec::StaticArrays.StaticVector{2}) where {T <: StaticArrays.St
|
||||
|
||||
to_vec(::Type{T}, vecs::AbstractVector) where {T <: StaticArrays.StaticVector} = map(x-> to_vec(T, x), vecs)
|
||||
|
||||
function extract_marker(plotattributes, kw_args)
|
||||
dim = Plots.is3d(plotattributes) ? 3 : 2
|
||||
function extract_marker(d, kw_args)
|
||||
dim = Plots.is3d(d) ? 3 : 2
|
||||
scaling = dim == 3 ? 0.003 : 2
|
||||
if haskey(plotattributes, :markershape)
|
||||
shape = plotattributes[:markershape]
|
||||
if haskey(d, :markershape)
|
||||
shape = d[:markershape]
|
||||
shape = gl_marker(shape)
|
||||
if shape != :none
|
||||
kw_args[:primitive] = shape
|
||||
end
|
||||
end
|
||||
dim = isa(kw_args[:primitive], GLVisualize.Sprites) ? 2 : 3
|
||||
if haskey(plotattributes, :markersize)
|
||||
msize = plotattributes[:markersize]
|
||||
if haskey(d, :markersize)
|
||||
msize = d[:markersize]
|
||||
kw_args[:scale] = to_vec(GeometryTypes.Vec{dim, Float32}, msize .* scaling)
|
||||
end
|
||||
if haskey(plotattributes, :offset)
|
||||
kw_args[:offset] = plotattributes[:offset]
|
||||
if haskey(d, :offset)
|
||||
kw_args[:offset] = d[:offset]
|
||||
end
|
||||
# get the color
|
||||
key = :markercolor
|
||||
haskey(plotattributes, key) || return
|
||||
c = gl_color(plotattributes[key])
|
||||
if isa(c, AbstractVector) && plotattributes[:marker_z] != nothing
|
||||
extract_colornorm(plotattributes, kw_args)
|
||||
haskey(d, key) || return
|
||||
c = gl_color(d[key])
|
||||
if isa(c, AbstractVector) && d[:marker_z] != nothing
|
||||
extract_colornorm(d, kw_args)
|
||||
kw_args[:color] = nothing
|
||||
kw_args[:color_map] = c
|
||||
kw_args[:intensity] = convert(Vector{Float32}, plotattributes[:marker_z])
|
||||
kw_args[:intensity] = convert(Vector{Float32}, d[:marker_z])
|
||||
else
|
||||
kw_args[:color] = c
|
||||
end
|
||||
key = :markerstrokecolor
|
||||
haskey(plotattributes, key) || return
|
||||
c = gl_color(plotattributes[key])
|
||||
haskey(d, key) || return
|
||||
c = gl_color(d[key])
|
||||
if c != nothing
|
||||
if !(isa(c, Colorant) || (isa(c, Vector) && eltype(c) <: Colorant))
|
||||
error("Stroke Color not supported: $c")
|
||||
end
|
||||
kw_args[:stroke_color] = c
|
||||
kw_args[:stroke_width] = Float32(plotattributes[:markerstrokewidth])
|
||||
kw_args[:stroke_width] = Float32(d[:markerstrokewidth])
|
||||
end
|
||||
end
|
||||
|
||||
function _extract_surface(plotattributes::Plots.Surface)
|
||||
plotattributes.surf
|
||||
function _extract_surface(d::Plots.Surface)
|
||||
d.surf
|
||||
end
|
||||
function _extract_surface(plotattributes::AbstractArray)
|
||||
plotattributes
|
||||
function _extract_surface(d::AbstractArray)
|
||||
d
|
||||
end
|
||||
|
||||
# TODO when to transpose??
|
||||
function extract_surface(plotattributes)
|
||||
map(_extract_surface, (plotattributes[:x], plotattributes[:y], plotattributes[:z]))
|
||||
function extract_surface(d)
|
||||
map(_extract_surface, (d[:x], d[:y], d[:z]))
|
||||
end
|
||||
function topoints(::Type{P}, array) where P
|
||||
[P(x) for x in zip(array...)]
|
||||
end
|
||||
function extract_points(plotattributes)
|
||||
dim = is3d(plotattributes) ? 3 : 2
|
||||
array = if plotattributes[:seriestype] == :straightline
|
||||
straightline_data(plotattributes)
|
||||
elseif plotattributes[:seriestype] == :shape
|
||||
shape_data(plotattributes)
|
||||
function extract_points(d)
|
||||
dim = is3d(d) ? 3 : 2
|
||||
array = if d[:seriestype] == :straightline
|
||||
straightline_data(d)
|
||||
elseif d[:seriestype] == :shape
|
||||
shape_data(d)
|
||||
else
|
||||
(plotattributes[:x], plotattributes[:y], plotattributes[:z])[1:dim]
|
||||
(d[:x], d[:y], d[:z])[1:dim]
|
||||
end
|
||||
topoints(Point{dim, Float32}, array)
|
||||
end
|
||||
@@ -275,50 +304,50 @@ function make_gradient(grad::ColorGradient)
|
||||
end
|
||||
make_gradient(c) = make_gradient(cgrad())
|
||||
|
||||
function extract_any_color(plotattributes, kw_args)
|
||||
if plotattributes[:marker_z] == nothing
|
||||
c = scalar_color(plotattributes, :fill)
|
||||
extract_c(plotattributes, kw_args, :fill)
|
||||
function extract_any_color(d, kw_args)
|
||||
if d[:marker_z] == nothing
|
||||
c = scalar_color(d, :fill)
|
||||
extract_c(d, kw_args, :fill)
|
||||
if isa(c, Colorant)
|
||||
kw_args[:color] = c
|
||||
else
|
||||
kw_args[:color] = nothing
|
||||
kw_args[:color_map] = make_gradient(c)
|
||||
clims = plotattributes[:subplot][:clims]
|
||||
clims = d[:subplot][:clims]
|
||||
if Plots.is_2tuple(clims)
|
||||
if isfinite(clims[1]) && isfinite(clims[2])
|
||||
kw_args[:color_norm] = Vec2f0(clims)
|
||||
end
|
||||
elseif clims == :auto
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(plotattributes[:y]))
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(d[:y]))
|
||||
end
|
||||
end
|
||||
else
|
||||
kw_args[:color] = nothing
|
||||
clims = plotattributes[:subplot][:clims]
|
||||
clims = d[:subplot][:clims]
|
||||
if Plots.is_2tuple(clims)
|
||||
if isfinite(clims[1]) && isfinite(clims[2])
|
||||
kw_args[:color_norm] = Vec2f0(clims)
|
||||
end
|
||||
elseif clims == :auto
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(plotattributes[:y]))
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(d[:y]))
|
||||
else
|
||||
error("Unsupported limits: $clims")
|
||||
end
|
||||
kw_args[:intensity] = convert(Vector{Float32}, plotattributes[:marker_z])
|
||||
kw_args[:color_map] = gl_color_map(plotattributes, :marker)
|
||||
kw_args[:intensity] = convert(Vector{Float32}, d[:marker_z])
|
||||
kw_args[:color_map] = gl_color_map(d, :marker)
|
||||
end
|
||||
end
|
||||
|
||||
function extract_stroke(plotattributes, kw_args)
|
||||
extract_c(plotattributes, kw_args, :line)
|
||||
if haskey(plotattributes, :linewidth)
|
||||
kw_args[:thickness] = Float32(plotattributes[:linewidth] * 3)
|
||||
function extract_stroke(d, kw_args)
|
||||
extract_c(d, kw_args, :line)
|
||||
if haskey(d, :linewidth)
|
||||
kw_args[:thickness] = Float32(d[:linewidth] * 3)
|
||||
end
|
||||
end
|
||||
|
||||
function extract_color(plotattributes, sym)
|
||||
plotattributes[Symbol("$(sym)color")]
|
||||
function extract_color(d, sym)
|
||||
d[Symbol("$(sym)color")]
|
||||
end
|
||||
|
||||
gl_color(c::PlotUtils.ColorGradient) = c.colors
|
||||
@@ -335,12 +364,12 @@ function gl_color(c, a)
|
||||
c = convertColor(c, a)
|
||||
RGBA{Float32}(c)
|
||||
end
|
||||
function scalar_color(plotattributes, sym)
|
||||
gl_color(extract_color(plotattributes, sym))
|
||||
function scalar_color(d, sym)
|
||||
gl_color(extract_color(d, sym))
|
||||
end
|
||||
|
||||
function gl_color_map(plotattributes, sym)
|
||||
colors = extract_color(plotattributes, sym)
|
||||
function gl_color_map(d, sym)
|
||||
colors = extract_color(d, sym)
|
||||
_gl_color_map(colors)
|
||||
end
|
||||
function _gl_color_map(colors::PlotUtils.ColorGradient)
|
||||
@@ -377,10 +406,10 @@ function insert_pattern!(points, kw_args)
|
||||
kw_args[:pattern] = tex
|
||||
kw_args[:pattern_length] = Float32(last(points))
|
||||
end
|
||||
function extract_linestyle(plotattributes, kw_args)
|
||||
haskey(plotattributes, :linestyle) || return
|
||||
ls = plotattributes[:linestyle]
|
||||
lw = plotattributes[:linewidth]
|
||||
function extract_linestyle(d, kw_args)
|
||||
haskey(d, :linestyle) || return
|
||||
ls = d[:linestyle]
|
||||
lw = d[:linewidth]
|
||||
kw_args[:thickness] = Float32(lw)
|
||||
if ls == :dash
|
||||
points = [0.0, lw, 2lw, 3lw, 4lw]
|
||||
@@ -400,7 +429,7 @@ function extract_linestyle(plotattributes, kw_args)
|
||||
points = [0.0, dtick, dtick+dgap, dtick+dgap+ptick, dtick+dgap+ptick+pgap, dtick+dgap+ptick+pgap+ptick, dtick+dgap+ptick+pgap+ptick+pgap]
|
||||
insert_pattern!(points, kw_args)
|
||||
end
|
||||
extract_c(plotattributes, kw_args, :line)
|
||||
extract_c(d, kw_args, :line)
|
||||
nothing
|
||||
end
|
||||
|
||||
@@ -467,8 +496,8 @@ function hover(to_hover, to_display, window)
|
||||
nothing
|
||||
end
|
||||
|
||||
function extract_extrema(plotattributes, kw_args)
|
||||
xmin, xmax = ignorenan_extrema(plotattributes[:x]); ymin, ymax = ignorenan_extrema(plotattributes[:y])
|
||||
function extract_extrema(d, kw_args)
|
||||
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
|
||||
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
|
||||
nothing
|
||||
end
|
||||
@@ -479,50 +508,50 @@ function extract_font(font, kw_args)
|
||||
kw_args[:color] = gl_color(font.color)
|
||||
end
|
||||
|
||||
function extract_colornorm(plotattributes, kw_args)
|
||||
clims = plotattributes[:subplot][:clims]
|
||||
function extract_colornorm(d, kw_args)
|
||||
clims = d[:subplot][:clims]
|
||||
if Plots.is_2tuple(clims)
|
||||
if isfinite(clims[1]) && isfinite(clims[2])
|
||||
kw_args[:color_norm] = Vec2f0(clims)
|
||||
end
|
||||
elseif clims == :auto
|
||||
z = if haskey(plotattributes, :marker_z) && plotattributes[:marker_z] != nothing
|
||||
plotattributes[:marker_z]
|
||||
elseif haskey(plotattributes, :line_z) && plotattributes[:line_z] != nothing
|
||||
plotattributes[:line_z]
|
||||
elseif isa(plotattributes[:z], Plots.Surface)
|
||||
plotattributes[:z].surf
|
||||
z = if haskey(d, :marker_z) && d[:marker_z] != nothing
|
||||
d[:marker_z]
|
||||
elseif haskey(d, :line_z) && d[:line_z] != nothing
|
||||
d[:line_z]
|
||||
elseif isa(d[:z], Plots.Surface)
|
||||
d[:z].surf
|
||||
else
|
||||
plotattributes[:y]
|
||||
d[:y]
|
||||
end
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(z))
|
||||
kw_args[:intensity] = map(Float32, collect(z))
|
||||
end
|
||||
end
|
||||
|
||||
function extract_gradient(plotattributes, kw_args, sym)
|
||||
function extract_gradient(d, kw_args, sym)
|
||||
key = Symbol("$(sym)color")
|
||||
haskey(plotattributes, key) || return
|
||||
c = make_gradient(plotattributes[key])
|
||||
haskey(d, key) || return
|
||||
c = make_gradient(d[key])
|
||||
kw_args[:color] = nothing
|
||||
extract_colornorm(plotattributes, kw_args)
|
||||
extract_colornorm(d, kw_args)
|
||||
kw_args[:color_map] = c
|
||||
return
|
||||
end
|
||||
|
||||
function extract_c(plotattributes, kw_args, sym)
|
||||
function extract_c(d, kw_args, sym)
|
||||
key = Symbol("$(sym)color")
|
||||
haskey(plotattributes, key) || return
|
||||
c = gl_color(plotattributes[key])
|
||||
haskey(d, key) || return
|
||||
c = gl_color(d[key])
|
||||
kw_args[:color] = nothing
|
||||
kw_args[:color_map] = nothing
|
||||
kw_args[:color_norm] = nothing
|
||||
if (
|
||||
isa(c, AbstractVector) &&
|
||||
((haskey(plotattributes, :marker_z) && plotattributes[:marker_z] != nothing) ||
|
||||
(haskey(plotattributes, :line_z) && plotattributes[:line_z] != nothing))
|
||||
((haskey(d, :marker_z) && d[:marker_z] != nothing) ||
|
||||
(haskey(d, :line_z) && d[:line_z] != nothing))
|
||||
)
|
||||
extract_colornorm(plotattributes, kw_args)
|
||||
extract_colornorm(d, kw_args)
|
||||
kw_args[:color_map] = c
|
||||
else
|
||||
kw_args[:color] = c
|
||||
@@ -530,16 +559,16 @@ function extract_c(plotattributes, kw_args, sym)
|
||||
return
|
||||
end
|
||||
|
||||
function extract_stroke(plotattributes, kw_args, sym)
|
||||
function extract_stroke(d, kw_args, sym)
|
||||
key = Symbol("$(sym)strokecolor")
|
||||
haskey(plotattributes, key) || return
|
||||
c = gl_color(plotattributes[key])
|
||||
haskey(d, key) || return
|
||||
c = gl_color(d[key])
|
||||
if c != nothing
|
||||
if !isa(c, Colorant)
|
||||
error("Stroke Color not supported: $c")
|
||||
end
|
||||
kw_args[:stroke_color] = c
|
||||
kw_args[:stroke_width] = Float32(plotattributes[Symbol("$(sym)strokewidth")]) * 2
|
||||
kw_args[:stroke_width] = Float32(d[Symbol("$(sym)strokewidth")]) * 2
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -551,12 +580,12 @@ function draw_grid_lines(sp, grid_segs, thickness, style, model, color)
|
||||
kw_args = Dict{Symbol, Any}(
|
||||
:model => model
|
||||
)
|
||||
plotattributes = Dict(
|
||||
d = Dict(
|
||||
:linestyle => style,
|
||||
:linewidth => Float32(thickness),
|
||||
:linecolor => color
|
||||
)
|
||||
Plots.extract_linestyle(plotattributes, kw_args)
|
||||
Plots.extract_linestyle(d, kw_args)
|
||||
GL.gl_lines(map(Point2f0, grid_segs.pts), kw_args)
|
||||
end
|
||||
|
||||
@@ -667,7 +696,7 @@ function text_model(font, pivot)
|
||||
end
|
||||
end
|
||||
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
|
||||
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
|
||||
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
|
||||
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
|
||||
|
||||
xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
|
||||
@@ -681,14 +710,6 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
|
||||
grid = draw_grid_lines(sp, ygrid_segs, yaxis[:gridlinewidth], yaxis[:gridstyle], model, RGBA(ygc, yaxis[:gridalpha]))
|
||||
push!(axis_vis, grid)
|
||||
end
|
||||
if xaxis[:minorgrid]
|
||||
minorgrid = draw_minorgrid_lines(sp, xminorgrid_segs, xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], model, RGBA(xgc, xaxis[:minorgridalpha]))
|
||||
push!(axis_vis, minorgrid)
|
||||
end
|
||||
if yaxis[:minorgrid]
|
||||
minorgrid = draw_minorgrid_lines(sp, yminorgrid_segs, yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], model, RGBA(ygc, yaxis[:minorgridalpha]))
|
||||
push!(axis_vis, minorgrid)
|
||||
end
|
||||
|
||||
xac = Colors.color(Plots.gl_color(xaxis[:foreground_color_axis]))
|
||||
yac = Colors.color(Plots.gl_color(yaxis[:foreground_color_axis]))
|
||||
@@ -808,10 +829,10 @@ function gl_draw_axes_3d(sp, model)
|
||||
)
|
||||
end
|
||||
|
||||
function gl_bar(plotattributes, kw_args)
|
||||
x, y = plotattributes[:x], plotattributes[:y]
|
||||
function gl_bar(d, kw_args)
|
||||
x, y = d[:x], d[:y]
|
||||
nx, ny = length(x), length(y)
|
||||
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
|
||||
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
|
||||
cv = [discrete_value!(axis, xi)[1] for xi=x]
|
||||
x = if nx == ny
|
||||
cv
|
||||
@@ -832,18 +853,18 @@ function gl_bar(plotattributes, kw_args)
|
||||
end
|
||||
|
||||
# make fillto a vector... default fills to 0
|
||||
fillto = plotattributes[:fillrange]
|
||||
fillto = d[:fillrange]
|
||||
if fillto == nothing
|
||||
fillto = 0
|
||||
end
|
||||
# create the bar shapes by adding x/y segments
|
||||
positions, scales = Array{Point2f0}(undef, ny), Array{Vec2f0}(undef, 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
|
||||
center = x[i]
|
||||
hwi = abs(_cycle(hw,i)); yi = y[i]; fi = _cycle(fillto,i)
|
||||
if Plots.isvertical(plotattributes)
|
||||
if Plots.isvertical(d)
|
||||
sz = (hwi*sx, yi*sy)
|
||||
else
|
||||
sz = (yi*sx, hwi*2*sy)
|
||||
@@ -862,10 +883,10 @@ const _box_halfwidth = 0.4
|
||||
|
||||
notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
||||
|
||||
function gl_boxplot(plotattributes, kw_args)
|
||||
function gl_boxplot(d, kw_args)
|
||||
kwbox = copy(kw_args)
|
||||
range = 1.5; notch = false
|
||||
x, y = plotattributes[:x], plotattributes[:y]
|
||||
x, y = d[:x], d[:y]
|
||||
glabels = sort(collect(unique(x)))
|
||||
warning = false
|
||||
outliers_x, outliers_y = zeros(0), zeros(0)
|
||||
@@ -890,8 +911,8 @@ function gl_boxplot(plotattributes, kw_args)
|
||||
end
|
||||
|
||||
# make the shape
|
||||
center = Plots.discrete_value!(plotattributes[:subplot][:xaxis], glabel)[1]
|
||||
hw = plotattributes[:bar_width] == nothing ? Plots._box_halfwidth*2 : _cycle(plotattributes[:bar_width], i)
|
||||
center = Plots.discrete_value!(d[:subplot][:xaxis], glabel)[1]
|
||||
hw = d[:bar_width] == nothing ? Plots._box_halfwidth*2 : _cycle(d[:bar_width], i)
|
||||
l, m, r = center - hw/2, center, center + hw/2
|
||||
|
||||
# internal nodes for notches
|
||||
@@ -930,17 +951,17 @@ function gl_boxplot(plotattributes, kw_args)
|
||||
:model => kw_args[:model],
|
||||
:offset => Vec2f0(0),
|
||||
)
|
||||
extract_marker(plotattributes, kw_args)
|
||||
extract_marker(d, kw_args)
|
||||
outlier_kw = Dict(
|
||||
:model => kw_args[:model],
|
||||
:color => scalar_color(plotattributes, :fill),
|
||||
:stroke_width => Float32(plotattributes[:markerstrokewidth]),
|
||||
:stroke_color => scalar_color(plotattributes, :markerstroke),
|
||||
:color => scalar_color(d, :fill),
|
||||
:stroke_width => Float32(d[:markerstrokewidth]),
|
||||
:stroke_color => scalar_color(d, :markerstroke),
|
||||
)
|
||||
lines_kw = Dict(
|
||||
:model => kw_args[:model],
|
||||
:stroke_width => plotattributes[:linewidth],
|
||||
:stroke_color => scalar_color(plotattributes, :fill),
|
||||
:stroke_width => d[:linewidth],
|
||||
:stroke_color => scalar_color(d, :fill),
|
||||
)
|
||||
vis1 = GLVisualize.visualize((GLVisualize.RECTANGLE, box_pos), Style(:default), kwbox)
|
||||
vis2 = GLVisualize.visualize((GLVisualize.CIRCLE, outliers), Style(:default), outlier_kw)
|
||||
@@ -988,7 +1009,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}(undef, 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)
|
||||
@@ -1066,8 +1087,8 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||
end
|
||||
for series in Plots.series_list(sp)
|
||||
|
||||
plotattributes = series.plotattributes
|
||||
st = plotattributes[:seriestype]; kw_args = KW() # exctract kw
|
||||
d = series.d
|
||||
st = d[:seriestype]; kw_args = KW() # exctract kw
|
||||
|
||||
kw_args[:model] = model_m # add transformation
|
||||
if !_3d # 3D is treated differently, since we need boundingboxes for camera
|
||||
@@ -1075,80 +1096,80 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||
end
|
||||
scale_for_annotations!(series)
|
||||
if st in (:surface, :wireframe)
|
||||
x, y, z = extract_surface(plotattributes)
|
||||
extract_gradient(plotattributes, kw_args, :fill)
|
||||
z = Plots.transpose_z(plotattributes, z, false)
|
||||
x, y, z = extract_surface(d)
|
||||
extract_gradient(d, kw_args, :fill)
|
||||
z = Plots.transpose_z(d, z, false)
|
||||
if isa(x, AbstractMatrix) && isa(y, AbstractMatrix)
|
||||
x, y = Plots.transpose_z(plotattributes, x, false), Plots.transpose_z(plotattributes, y, false)
|
||||
x, y = Plots.transpose_z(d, x, false), Plots.transpose_z(d, y, false)
|
||||
end
|
||||
if st == :wireframe
|
||||
kw_args[:wireframe] = true
|
||||
kw_args[:stroke_color] = plotattributes[:linecolor]
|
||||
kw_args[:stroke_width] = Float32(plotattributes[:linewidth]/100f0)
|
||||
kw_args[:stroke_color] = d[:linecolor]
|
||||
kw_args[:stroke_width] = Float32(d[:linewidth]/100f0)
|
||||
end
|
||||
vis = GL.gl_surface(x, y, z, kw_args)
|
||||
elseif (st in (:path, :path3d, :straightline)) && plotattributes[:linewidth] > 0
|
||||
elseif (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
|
||||
kw = copy(kw_args)
|
||||
points = Plots.extract_points(plotattributes)
|
||||
extract_linestyle(plotattributes, kw)
|
||||
points = Plots.extract_points(d)
|
||||
extract_linestyle(d, kw)
|
||||
vis = GL.gl_lines(points, kw)
|
||||
if plotattributes[:markershape] != :none
|
||||
if d[:markershape] != :none
|
||||
kw = copy(kw_args)
|
||||
extract_stroke(plotattributes, kw)
|
||||
extract_marker(plotattributes, kw)
|
||||
extract_stroke(d, kw)
|
||||
extract_marker(d, kw)
|
||||
vis2 = GL.gl_scatter(copy(points), kw)
|
||||
vis = [vis; vis2]
|
||||
end
|
||||
if plotattributes[:fillrange] != nothing
|
||||
if d[:fillrange] != nothing
|
||||
kw = copy(kw_args)
|
||||
fr = plotattributes[:fillrange]
|
||||
ps = if all(x-> x >= 0, diff(plotattributes[:x])) # if is monotonic
|
||||
fr = d[:fillrange]
|
||||
ps = if all(x-> x >= 0, diff(d[:x])) # if is monotonic
|
||||
vcat(points, Point2f0[(points[i][1], _cycle(fr, i)) for i=length(points):-1:1])
|
||||
else
|
||||
points
|
||||
end
|
||||
extract_c(plotattributes, kw, :fill)
|
||||
extract_c(d, kw, :fill)
|
||||
vis = [GL.gl_poly(ps, kw), vis]
|
||||
end
|
||||
elseif st in (:scatter, :scatter3d) #|| plotattributes[:markershape] != :none
|
||||
extract_marker(plotattributes, kw_args)
|
||||
points = extract_points(plotattributes)
|
||||
elseif st in (:scatter, :scatter3d) #|| d[:markershape] != :none
|
||||
extract_marker(d, kw_args)
|
||||
points = extract_points(d)
|
||||
vis = GL.gl_scatter(points, kw_args)
|
||||
elseif st == :shape
|
||||
extract_c(plotattributes, kw_args, :fill)
|
||||
vis = GL.gl_shape(plotattributes, kw_args)
|
||||
extract_c(d, kw_args, :fill)
|
||||
vis = GL.gl_shape(d, kw_args)
|
||||
elseif st == :contour
|
||||
x,y,z = extract_surface(plotattributes)
|
||||
z = transpose_z(plotattributes, z, false)
|
||||
extract_extrema(plotattributes, kw_args)
|
||||
extract_gradient(plotattributes, kw_args, :fill)
|
||||
kw_args[:fillrange] = plotattributes[:fillrange]
|
||||
kw_args[:levels] = plotattributes[:levels]
|
||||
x,y,z = extract_surface(d)
|
||||
z = transpose_z(d, z, false)
|
||||
extract_extrema(d, kw_args)
|
||||
extract_gradient(d, kw_args, :fill)
|
||||
kw_args[:fillrange] = d[:fillrange]
|
||||
kw_args[:levels] = d[:levels]
|
||||
|
||||
vis = GL.gl_contour(x,y,z, kw_args)
|
||||
elseif st == :heatmap
|
||||
x,y,z = extract_surface(plotattributes)
|
||||
extract_gradient(plotattributes, kw_args, :fill)
|
||||
extract_extrema(plotattributes, kw_args)
|
||||
extract_limits(sp, plotattributes, kw_args)
|
||||
x,y,z = extract_surface(d)
|
||||
extract_gradient(d, kw_args, :fill)
|
||||
extract_extrema(d, kw_args)
|
||||
extract_limits(sp, d, kw_args)
|
||||
vis = GL.gl_heatmap(x,y,z, kw_args)
|
||||
elseif st == :bar
|
||||
extract_c(plotattributes, kw_args, :fill)
|
||||
extract_stroke(plotattributes, kw_args, :marker)
|
||||
vis = gl_bar(plotattributes, kw_args)
|
||||
extract_c(d, kw_args, :fill)
|
||||
extract_stroke(d, kw_args, :marker)
|
||||
vis = gl_bar(d, kw_args)
|
||||
elseif st == :image
|
||||
extract_extrema(plotattributes, kw_args)
|
||||
vis = GL.gl_image(plotattributes[:z].surf, kw_args)
|
||||
extract_extrema(d, kw_args)
|
||||
vis = GL.gl_image(d[:z].surf, kw_args)
|
||||
elseif st == :boxplot
|
||||
extract_c(plotattributes, kw_args, :fill)
|
||||
vis = gl_boxplot(plotattributes, kw_args)
|
||||
extract_c(d, kw_args, :fill)
|
||||
vis = gl_boxplot(d, kw_args)
|
||||
elseif st == :volume
|
||||
volume = plotattributes[:y]
|
||||
_plotattributes = copy(plotattributes)
|
||||
_plotattributes[:y] = 0:1
|
||||
_plotattributes[:x] = 0:1
|
||||
volume = d[:y]
|
||||
_d = copy(d)
|
||||
_d[:y] = 0:1
|
||||
_d[:x] = 0:1
|
||||
kw_args = KW()
|
||||
extract_gradient(_plotattributes, kw_args, :fill)
|
||||
extract_gradient(_d, kw_args, :fill)
|
||||
vis = visualize(volume.v, Style(:default), kw_args)
|
||||
else
|
||||
error("failed to display plot type $st")
|
||||
@@ -1157,15 +1178,15 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||
isa(vis, Array) && isempty(vis) && continue # nothing to see here
|
||||
|
||||
GLVisualize._view(vis, sp_screen, camera=:perspective)
|
||||
if haskey(plotattributes, :hover) && !(plotattributes[:hover] in (false, :none, nothing))
|
||||
hover(vis, plotattributes[:hover], sp_screen)
|
||||
if haskey(d, :hover) && !(d[:hover] in (false, :none, nothing))
|
||||
hover(vis, d[:hover], sp_screen)
|
||||
end
|
||||
if isdefined(:GLPlot) && isdefined(Main.GLPlot, :(register_plot!))
|
||||
del_signal = Main.GLPlot.register_plot!(vis, sp_screen, create_gizmo=false)
|
||||
append!(_glplot_deletes, del_signal)
|
||||
end
|
||||
anns = series[:series_annotations]
|
||||
for (x, y, str, font) in EachAnn(anns, plotattributes[:x], plotattributes[:y])
|
||||
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) * GeometryTypes.Vec{4, Float32}(x, y, 0, 1)
|
||||
extract_font(font, txt_args)
|
||||
@@ -1241,10 +1262,10 @@ function gl_lines(points, kw_args)
|
||||
return result
|
||||
end
|
||||
|
||||
function gl_shape(plotattributes, kw_args)
|
||||
points = Plots.extract_points(plotattributes)
|
||||
function gl_shape(d, kw_args)
|
||||
points = Plots.extract_points(d)
|
||||
result = []
|
||||
for rng in iter_segments(plotattributes[:x], plotattributes[:y])
|
||||
for rng in iter_segments(d[:x], d[:y])
|
||||
ps = points[rng]
|
||||
meshes = gl_poly(ps, kw_args)
|
||||
append!(result, meshes)
|
||||
@@ -1300,7 +1321,7 @@ function gl_poly(points, kw_args)
|
||||
if !isempty(GeometryTypes.faces(mesh)) # check if polygonation has any faces
|
||||
push!(result, GLVisualize.visualize(mesh, Style(:default), kw_args))
|
||||
else
|
||||
@warn("Couldn't draw the polygon: $points")
|
||||
warn("Couldn't draw the polygon: $points")
|
||||
end
|
||||
end
|
||||
result
|
||||
@@ -1398,10 +1419,10 @@ end
|
||||
"""
|
||||
Ugh, so much special casing (╯°□°)╯︵ ┻━┻
|
||||
"""
|
||||
function label_scatter(plotattributes, w, ho)
|
||||
function label_scatter(d, w, ho)
|
||||
kw = KW()
|
||||
extract_stroke(plotattributes, kw)
|
||||
extract_marker(plotattributes, kw)
|
||||
extract_stroke(d, kw)
|
||||
extract_marker(d, kw)
|
||||
kw[:scale] = Vec2f0(w/2)
|
||||
kw[:offset] = Vec2f0(-w/4)
|
||||
if haskey(kw, :intensity)
|
||||
@@ -1442,21 +1463,21 @@ function make_label(sp, series, i)
|
||||
GL = Plots
|
||||
w, gap, ho = 20f0, 5f0, 5
|
||||
result = []
|
||||
plotattributes = series.plotattributes
|
||||
st = plotattributes[:seriestype]
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
kw_args = KW()
|
||||
if (st in (:path, :path3d, :straightline)) && plotattributes[:linewidth] > 0
|
||||
if (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
|
||||
points = Point2f0[(0, ho), (w, ho)]
|
||||
kw = KW()
|
||||
extract_linestyle(plotattributes, kw)
|
||||
extract_linestyle(d, kw)
|
||||
append!(result, GL.gl_lines(points, kw))
|
||||
if plotattributes[:markershape] != :none
|
||||
push!(result, label_scatter(plotattributes, w, ho))
|
||||
if d[:markershape] != :none
|
||||
push!(result, label_scatter(d, w, ho))
|
||||
end
|
||||
elseif st in (:scatter, :scatter3d) #|| plotattributes[:markershape] != :none
|
||||
push!(result, label_scatter(plotattributes, w, ho))
|
||||
elseif st in (:scatter, :scatter3d) #|| d[:markershape] != :none
|
||||
push!(result, label_scatter(d, w, ho))
|
||||
else
|
||||
extract_c(plotattributes, kw_args, :fill)
|
||||
extract_c(d, kw_args, :fill)
|
||||
if isa(kw_args[:color], AbstractVector)
|
||||
kw_args[:color] = first(kw_args[:color])
|
||||
end
|
||||
|
||||
+48
-64
@@ -3,6 +3,10 @@
|
||||
|
||||
# significant contributions by @jheinen
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "gr.jl"))
|
||||
end
|
||||
|
||||
const _gr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
@@ -18,7 +22,6 @@ const _gr_attr = merge_with_base_supported([
|
||||
:layout,
|
||||
:title, :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip,
|
||||
:match_dimensions,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontrotation, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
|
||||
@@ -28,7 +31,7 @@ const _gr_attr = merge_with_base_supported([
|
||||
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
|
||||
:guidefontrotation, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title,
|
||||
:legend, :legendtitle, :colorbar,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
@@ -62,8 +65,12 @@ function add_backend_string(::GRBackend)
|
||||
"""
|
||||
end
|
||||
|
||||
import GR
|
||||
export GR
|
||||
function _initialize_backend(::GRBackend; kw...)
|
||||
@eval begin
|
||||
import GR
|
||||
export GR
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -339,11 +346,7 @@ end
|
||||
|
||||
|
||||
# draw the markers, one at a time
|
||||
function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize])
|
||||
|
||||
isempty(x) && return
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
|
||||
function gr_draw_markers(series::Series, x, y, msize, mz)
|
||||
shapes = series[:markershape]
|
||||
if shapes != :none
|
||||
for i=1:length(x)
|
||||
@@ -360,7 +363,7 @@ function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize
|
||||
|
||||
# draw the shape - don't draw filled area if marker shape is 1D
|
||||
if !(shape in (:hline, :vline, :+, :x))
|
||||
cfunc(get_markercolor(series, clims, i))
|
||||
cfunc(get_markercolor(series, i))
|
||||
gr_set_transparency(get_markeralpha(series, i))
|
||||
gr_draw_marker(x[i], y[i], msi, shape)
|
||||
end
|
||||
@@ -368,6 +371,13 @@ function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize
|
||||
end
|
||||
end
|
||||
|
||||
function gr_draw_markers(series::Series, x, y, clims)
|
||||
isempty(x) && return
|
||||
mz = normalize_zvals(series[:marker_z], clims)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
gr_draw_markers(series, x, y, series[:markersize], mz)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function gr_set_line(lw, style, c) #, a)
|
||||
@@ -419,8 +429,6 @@ const viewport_plotarea = zeros(4)
|
||||
# the size of the current plot in pixels
|
||||
const gr_plot_size = [600.0, 400.0]
|
||||
|
||||
const gr_colorbar_ratio = 0.1
|
||||
|
||||
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
|
||||
viewport = zeros(4)
|
||||
viewport[1] = viewport_canvas[2] * (left(bb) / w)
|
||||
@@ -436,7 +444,7 @@ function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, vi
|
||||
viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
|
||||
end
|
||||
if hascolorbar(sp)
|
||||
viewport[2] -= gr_colorbar_ratio
|
||||
viewport[2] -= 0.1
|
||||
end
|
||||
viewport
|
||||
end
|
||||
@@ -483,13 +491,6 @@ function gr_colorbar(sp::Subplot, clims)
|
||||
GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l)
|
||||
ztick = 0.5 * GR.tick(clims[1], clims[2])
|
||||
GR.axes(0, ztick, xmax, clims[1], 0, 1, 0.005)
|
||||
|
||||
gr_set_font(guidefont(sp[:yaxis]))
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.setcharup(-1, 0)
|
||||
gr_text(viewport_plotarea[2] + gr_colorbar_ratio,
|
||||
gr_view_ycenter(), sp[:colorbar_title])
|
||||
|
||||
gr_set_viewport_plotarea()
|
||||
end
|
||||
|
||||
@@ -623,7 +624,7 @@ end
|
||||
function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
dpi = sp.plt[:thickness_scaling]
|
||||
if !haskey(ENV, "GKSwstype")
|
||||
if isijulia()
|
||||
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
|
||||
ENV["GKSwstype"] = "svg"
|
||||
end
|
||||
end
|
||||
@@ -664,9 +665,6 @@ function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
if sp[:yaxis][:guide] != ""
|
||||
leftpad += 4mm
|
||||
end
|
||||
if sp[:colorbar_title] != ""
|
||||
rightpad += 4mm
|
||||
end
|
||||
sp.minpad = Tuple(dpi * [leftpad, toppad, rightpad, bottompad])
|
||||
end
|
||||
|
||||
@@ -820,7 +818,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.setwindow(xmin, xmax, ymin, ymax)
|
||||
end
|
||||
|
||||
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
|
||||
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
|
||||
# @show xticks yticks #spine_segs grid_segs
|
||||
|
||||
# draw the grid lines
|
||||
@@ -836,18 +834,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
gr_set_transparency(yaxis[:gridalpha])
|
||||
gr_polyline(coords(ygrid_segs)...)
|
||||
end
|
||||
if xaxis[:minorgrid]
|
||||
# gr_set_linecolor(sp[:foreground_color_grid])
|
||||
# GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
gr_set_line(xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], xaxis[:foreground_color_minor_grid])
|
||||
gr_set_transparency(xaxis[:minorgridalpha])
|
||||
gr_polyline(coords(xminorgrid_segs)...)
|
||||
end
|
||||
if yaxis[:minorgrid]
|
||||
gr_set_line(yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], yaxis[:foreground_color_minor_grid])
|
||||
gr_set_transparency(yaxis[:minorgridalpha])
|
||||
gr_polyline(coords(yminorgrid_segs)...)
|
||||
end
|
||||
gr_set_transparency(1.0)
|
||||
|
||||
# axis lines
|
||||
@@ -1036,7 +1022,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
|
||||
for (i, rng) in enumerate(segments)
|
||||
gr_set_fillcolor(get_fillcolor(series, clims, i))
|
||||
gr_set_fillcolor(get_fillcolor(series, i))
|
||||
fx = _cycle(x, vcat(rng, reverse(rng)))
|
||||
fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
|
||||
gr_set_transparency(get_fillalpha(series, i))
|
||||
@@ -1047,7 +1033,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
# draw the line(s)
|
||||
if st in (:path, :straightline)
|
||||
for (i, rng) in enumerate(segments)
|
||||
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, clims, i)) #, series[:linealpha])
|
||||
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, i)) #, series[:linealpha])
|
||||
gr_set_transparency(get_linealpha(series, i))
|
||||
arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
|
||||
gr_polyline(x[rng], y[rng]; arrowside = arrowside)
|
||||
@@ -1113,10 +1099,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
|
||||
colors = [plot_color(grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)], series[:fillalpha]) for zi=z]
|
||||
rgba = map(c -> UInt32( round(UInt, alpha(c) * 255) << 24 +
|
||||
round(UInt, blue(c) * 255) << 16 +
|
||||
round(UInt, green(c) * 255) << 8 +
|
||||
round(UInt, red(c) * 255) ), colors)
|
||||
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
|
||||
round(Int, blue(c) * 255) << 16 +
|
||||
round(Int, green(c) * 255) << 8 +
|
||||
round(Int, red(c) * 255) ), colors)
|
||||
w, h = length(x), length(y)
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||
|
||||
@@ -1127,7 +1113,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
lz = series[:line_z]
|
||||
segments = iter_segments(series)
|
||||
for (i, rng) in enumerate(segments)
|
||||
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, clims, i)) #, series[:linealpha])
|
||||
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, i)) #, series[:linealpha])
|
||||
gr_set_transparency(get_linealpha(series, i))
|
||||
GR.polyline3d(x[rng], y[rng], z[rng])
|
||||
end
|
||||
@@ -1199,12 +1185,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
xseg, yseg = x[rng], y[rng]
|
||||
|
||||
# draw the interior
|
||||
gr_set_fill(get_fillcolor(series, clims, i))
|
||||
gr_set_fill(get_fillcolor(series, i))
|
||||
gr_set_transparency(get_fillalpha(series, i))
|
||||
GR.fillarea(xseg, yseg)
|
||||
|
||||
# draw the shapes
|
||||
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, clims, i))
|
||||
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, i))
|
||||
gr_set_transparency(get_linealpha(series, i))
|
||||
GR.polyline(xseg, yseg)
|
||||
end
|
||||
@@ -1220,12 +1206,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
|
||||
if eltype(z) <: Colors.AbstractGray
|
||||
grey = round.(UInt8, float(z) * 255)
|
||||
rgba = map(c -> UInt32( 0xff000000 + UInt(c)<<16 + UInt(c)<<8 + UInt(c) ), grey)
|
||||
rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey)
|
||||
else
|
||||
rgba = map(c -> UInt32( round(UInt, alpha(c) * 255) << 24 +
|
||||
round(UInt, blue(c) * 255) << 16 +
|
||||
round(UInt, green(c) * 255) << 8 +
|
||||
round(UInt, red(c) * 255) ), z)
|
||||
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
|
||||
round(Int, blue(c) * 255) << 16 +
|
||||
round(Int, green(c) * 255) << 8 +
|
||||
round(Int, red(c) * 255) ), z)
|
||||
end
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||
end
|
||||
@@ -1237,18 +1223,16 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
gr_text(GR.wctondc(xi, yi)..., str)
|
||||
end
|
||||
|
||||
# draw the colorbar
|
||||
if cmap && st != :contour # special colorbar with steps is drawn for contours
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
gr_set_transparency(1)
|
||||
gr_colorbar(sp, clims)
|
||||
end
|
||||
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
# draw the colorbar
|
||||
GR.savestate()
|
||||
# special colorbar with steps is drawn for contours
|
||||
if cmap && any(series[:seriestype] != :contour for series in series_list(sp))
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
gr_set_transparency(1)
|
||||
gr_colorbar(sp, clims)
|
||||
end
|
||||
GR.restorestate()
|
||||
|
||||
# add the legend
|
||||
if sp[:legend] != :none
|
||||
@@ -1296,10 +1280,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
for series in series_list(sp)
|
||||
should_add_to_legend(series) || continue
|
||||
st = series[:seriestype]
|
||||
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series, clims)) #, series[:linealpha])
|
||||
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series)) #, series[:linealpha])
|
||||
|
||||
if (st == :shape || series[:fillrange] != nothing) && series[:ribbon] == nothing
|
||||
gr_set_fill(get_fillcolor(series, clims)) #, series[:fillalpha])
|
||||
gr_set_fill(get_fillcolor(series)) #, series[:fillalpha])
|
||||
l, r = xpos-0.07, xpos-0.01
|
||||
b, t = ypos-0.4dy, ypos+0.4dy
|
||||
x = [l, r, r, l, l]
|
||||
@@ -1307,7 +1291,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
gr_set_transparency(get_fillalpha(series))
|
||||
gr_polyline(x, y, GR.fillarea)
|
||||
gr_set_transparency(get_linealpha(series))
|
||||
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series, clims))
|
||||
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series))
|
||||
st == :shape && gr_polyline(x, y)
|
||||
end
|
||||
|
||||
@@ -1321,7 +1305,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
|
||||
if series[:markershape] != :none
|
||||
gr_draw_markers(series, xpos - .035, ypos, clims, 6)
|
||||
gr_draw_markers(series, xpos - .035, ypos, 6, nothing)
|
||||
end
|
||||
|
||||
if typeof(series[:label]) <: Array
|
||||
|
||||
+68
-52
@@ -28,6 +28,10 @@ Read from .hdf5 file using:
|
||||
- Should be reliable for archival purposes.
|
||||
==#
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
|
||||
end
|
||||
|
||||
import FixedPointNumbers: N0f8 #In core Julia
|
||||
|
||||
#Dispatch types:
|
||||
@@ -41,7 +45,6 @@ end
|
||||
|
||||
#==Useful constants
|
||||
===============================================================================#
|
||||
const _hdf5_nullable{T} = Union{T, Nothing}
|
||||
const _hdf5_plotroot = "plot"
|
||||
const _hdf5_dataroot = "data" #TODO: Eventually move data to different root (easier to locate)?
|
||||
const _hdf5plot_datatypeid = "TYPE" #Attribute identifying type
|
||||
@@ -105,35 +108,12 @@ const _hdf5_marker = vcat(_allMarkers, :pixel)
|
||||
const _hdf5_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::HDF5Backend, shape::Shape) = true
|
||||
|
||||
if length(HDF5PLOT_MAP_TELEM2STR) < 1
|
||||
#Possible element types of high-level data types:
|
||||
telem2str = Dict{String, Type}(
|
||||
"NATIVE" => HDF5PlotNative,
|
||||
"VOID" => Nothing,
|
||||
"BOOL" => Bool,
|
||||
"SYMBOL" => Symbol,
|
||||
"TUPLE" => Tuple,
|
||||
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
|
||||
"RGBA" => ARGB{N0f8},
|
||||
"EXTREMA" => Extrema,
|
||||
"LENGTH" => Length,
|
||||
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
|
||||
|
||||
#Sub-structure types:
|
||||
"FONT" => Font,
|
||||
"BOUNDINGBOX" => BoundingBox,
|
||||
"GRIDLAYOUT" => GridLayout,
|
||||
"ROOTLAYOUT" => RootLayout,
|
||||
"SERIESANNOTATIONS" => SeriesAnnotations,
|
||||
# "PLOTTEXT" => PlotText,
|
||||
"COLORGRADIENT" => ColorGradient,
|
||||
"AXIS" => Axis,
|
||||
"SURFACE" => Surface,
|
||||
"SUBPLOT" => Subplot,
|
||||
"NULLABLE" => _hdf5_nullable,
|
||||
)
|
||||
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
|
||||
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
|
||||
function add_backend_string(::HDF5Backend)
|
||||
"""
|
||||
if !Plots.is_installed("HDF5")
|
||||
Pkg.add("HDF5")
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -148,7 +128,7 @@ _hdf5_map_str2telem(v::Vector) = HDF5PLOT_MAP_STR2TELEM[v[1]]
|
||||
function _hdf5_merge!(dest::Dict, src::Dict)
|
||||
for (k, v) in src
|
||||
if isa(v, Axis)
|
||||
_hdf5_merge!(dest[k].plotattributes, v.plotattributes)
|
||||
_hdf5_merge!(dest[k].d, v.d)
|
||||
else
|
||||
dest[k] = v
|
||||
end
|
||||
@@ -160,6 +140,44 @@ end
|
||||
#==
|
||||
===============================================================================#
|
||||
|
||||
function _initialize_backend(::HDF5Backend)
|
||||
@eval begin
|
||||
import HDF5
|
||||
export HDF5
|
||||
if length(HDF5PLOT_MAP_TELEM2STR) < 1
|
||||
#Possible element types of high-level data types:
|
||||
telem2str = Dict{String, Type}(
|
||||
"NATIVE" => HDF5PlotNative,
|
||||
"VOID" => Nothing,
|
||||
"BOOL" => Bool,
|
||||
"SYMBOL" => Symbol,
|
||||
"TUPLE" => Tuple,
|
||||
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
|
||||
"RGBA" => ARGB{N0f8},
|
||||
"EXTREMA" => Extrema,
|
||||
"LENGTH" => Length,
|
||||
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
|
||||
|
||||
#Sub-structure types:
|
||||
"FONT" => Font,
|
||||
"BOUNDINGBOX" => BoundingBox,
|
||||
"GRIDLAYOUT" => GridLayout,
|
||||
"ROOTLAYOUT" => RootLayout,
|
||||
"SERIESANNOTATIONS" => SeriesAnnotations,
|
||||
# "PLOTTEXT" => PlotText,
|
||||
"COLORGRADIENT" => ColorGradient,
|
||||
"AXIS" => Axis,
|
||||
"SURFACE" => Surface,
|
||||
"SUBPLOT" => Subplot,
|
||||
"NULLABLE" => Nullable,
|
||||
)
|
||||
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
|
||||
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Create the window/figure for this backend.
|
||||
function _create_backend_figure(plt::Plot{HDF5Backend})
|
||||
@@ -215,7 +233,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
function _update_plot_object(plt::Plot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
@@ -226,7 +244,7 @@ end
|
||||
function _display(plt::Plot{HDF5Backend})
|
||||
msg = "HDF5 interface does not support `display()` function."
|
||||
msg *= "\nUse `Plots.hdf5plot_write(::String)` method to write to .HDF5 \"plot\" file instead."
|
||||
@warn(msg)
|
||||
warn(msg)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -271,7 +289,7 @@ function _hdf5plot_writecount(grp, n::Int) #Write directly to group
|
||||
end
|
||||
function _hdf5plot_gwritefields(grp, k::String, v)
|
||||
grp = HDF5.g_create(grp, k)
|
||||
for _k in fieldnames(typeof(v))
|
||||
for _k in fieldnames(v)
|
||||
_v = getfield(v, _k)
|
||||
kstr = string(_k)
|
||||
_hdf5plot_gwrite(grp, kstr, _v)
|
||||
@@ -294,7 +312,7 @@ end
|
||||
#=
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Array{Any})
|
||||
# @show grp, k
|
||||
@warn("Cannot write Array: $k=$v")
|
||||
warn("Cannot write Array: $k=$v")
|
||||
end
|
||||
=#
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Nothing)
|
||||
@@ -323,8 +341,8 @@ function _hdf5plot_gwrite(grp, k::String, v::Tuple)
|
||||
end
|
||||
#NOTE: _hdf5plot_overwritetype overwrites "Array" type with "Tuple".
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, plotattributes::Dict)
|
||||
# @warn("Cannot write dict: $k=$plotattributes")
|
||||
function _hdf5plot_gwrite(grp, k::String, d::Dict)
|
||||
# warn("Cannot write dict: $k=$d")
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::AbstractRange)
|
||||
_hdf5plot_gwrite(grp, k, collect(v)) #For now
|
||||
@@ -345,10 +363,9 @@ function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
|
||||
vgrp = HDF5.g_create(grp, k)
|
||||
_hdf5plot_writetype(vgrp, Array) #ANY
|
||||
sz = size(v)
|
||||
lidx = LinearIndices(sz)
|
||||
|
||||
for iter in eachindex(v)
|
||||
coord = lidx[iter]
|
||||
coord = LinearIndices(sz, iter)
|
||||
elem = v[iter]
|
||||
idxstr = join(coord, "_")
|
||||
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
|
||||
@@ -380,7 +397,7 @@ function _hdf5plot_gwrite(grp, k::String, v::HDF5PLOT_SIMPLESUBSTRUCT)
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Axis)
|
||||
grp = HDF5.g_create(grp, k)
|
||||
for (_k, _v) in v.plotattributes
|
||||
for (_k, _v) in v.d
|
||||
kstr = string(_k)
|
||||
_hdf5plot_gwrite(grp, kstr, _v)
|
||||
end
|
||||
@@ -393,7 +410,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Surface)
|
||||
_hdf5plot_writetype(grp, Surface)
|
||||
end
|
||||
# #TODO: "Properly" support Nullable using _hdf5plot_writetype?
|
||||
# function _hdf5plot_gwrite(grp, k::String, v::_hdf5_nullable)
|
||||
# function _hdf5plot_gwrite(grp, k::String, v::Nullable)
|
||||
# if isnull(v)
|
||||
# _hdf5plot_gwrite(grp, k, nothing)
|
||||
# else
|
||||
@@ -412,8 +429,8 @@ function _hdf5plot_gwrite(grp, k::String, v::Subplot)
|
||||
_hdf5plot_writetype(grp, Subplot)
|
||||
return
|
||||
end
|
||||
function _hdf5plot_write(grp, plotattributes::Dict)
|
||||
for (k, v) in plotattributes
|
||||
function _hdf5plot_write(grp, d::Dict)
|
||||
for (k, v) in d
|
||||
kstr = string(k)
|
||||
_hdf5plot_gwrite(grp, kstr, v)
|
||||
end
|
||||
@@ -431,7 +448,7 @@ function _hdf5plot_write(sp::Subplot{HDF5Backend}, subpath::String, f)
|
||||
_hdf5plot_writecount(grp, length(sp.series_list))
|
||||
for (i, series) in enumerate(sp.series_list)
|
||||
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/series_list/series$i"))
|
||||
_hdf5plot_write(grp, series.plotattributes)
|
||||
_hdf5plot_write(grp, series.d)
|
||||
end
|
||||
|
||||
return
|
||||
@@ -510,11 +527,10 @@ function _hdf5plot_read(grp, k::String, T::Type{Array}, dtid) #ANY
|
||||
sz = _hdf5plot_read(grp, "dim")
|
||||
if [0] == sz; return []; end
|
||||
sz = tuple(sz...)
|
||||
result = Array{Any}(undef, sz)
|
||||
lidx = LinearIndices(sz)
|
||||
result = Array{Any}(sz)
|
||||
|
||||
for iter in eachindex(result)
|
||||
coord = lidx[iter]
|
||||
coord = LinearIndices(sz, iter)
|
||||
idxstr = join(coord, "_")
|
||||
result[iter] = _hdf5plot_read(grp, "v$idxstr")
|
||||
end
|
||||
@@ -579,17 +595,17 @@ function _hdf5plot_read(grp, k::String)
|
||||
return _hdf5plot_read(grp, k, T, dtid)
|
||||
end
|
||||
|
||||
#Read in values in group to populate plotattributes:
|
||||
function _hdf5plot_read(grp, plotattributes::Dict)
|
||||
#Read in values in group to populate d:
|
||||
function _hdf5plot_read(grp, d::Dict)
|
||||
gnames = names(grp)
|
||||
for k in gnames
|
||||
try
|
||||
v = _hdf5plot_read(grp, k)
|
||||
plotattributes[Symbol(k)] = v
|
||||
d[Symbol(k)] = v
|
||||
catch e
|
||||
@show e
|
||||
@show grp
|
||||
@warn("Could not read field $k")
|
||||
warn("Could not read field $k")
|
||||
end
|
||||
end
|
||||
return
|
||||
@@ -614,7 +630,7 @@ function _hdf5plot_read(sp::Subplot, subpath::String, f)
|
||||
kwlist = KW()
|
||||
_hdf5plot_read(grp, kwlist)
|
||||
plot!(sp, kwlist[:x], kwlist[:y]) #Add data & create data structures
|
||||
_hdf5_merge!(sp.series_list[end].plotattributes, kwlist)
|
||||
_hdf5_merge!(sp.series_list[end].d, kwlist)
|
||||
end
|
||||
|
||||
return
|
||||
|
||||
+33
-15
@@ -13,6 +13,10 @@ Add in functionality to Plots.jl:
|
||||
:aspect_ratio,
|
||||
=#
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "inspectdr.jl"))
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
#TODO: remove features
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
@@ -148,23 +152,37 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
#Glyph used when plotting "Shape"s:
|
||||
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
|
||||
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
|
||||
)
|
||||
|
||||
mutable struct InspecDRPlotRef
|
||||
mplot::Union{Nothing, InspectDR.Multiplot}
|
||||
gui::Union{Nothing, InspectDR.GtkPlot}
|
||||
function add_backend_string(::InspectDRBackend)
|
||||
"""
|
||||
if !Plots.is_installed("InspectDR")
|
||||
Pkg.add("InspectDR")
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
_inspectdr_getmplot(::Any) = nothing
|
||||
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
|
||||
function _initialize_backend(::InspectDRBackend; kw...)
|
||||
@eval begin
|
||||
import InspectDR
|
||||
export InspectDR
|
||||
|
||||
_inspectdr_getgui(::Any) = nothing
|
||||
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
|
||||
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
|
||||
push!(_initialized_backends, :inspectdr)
|
||||
#Glyph used when plotting "Shape"s:
|
||||
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
|
||||
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
|
||||
)
|
||||
|
||||
mutable struct InspecDRPlotRef
|
||||
mplot::Union{Nothing, InspectDR.Multiplot}
|
||||
gui::Union{Nothing, InspectDR.GtkPlot}
|
||||
end
|
||||
|
||||
_inspectdr_getmplot(::Any) = nothing
|
||||
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
|
||||
|
||||
_inspectdr_getgui(::Any) = nothing
|
||||
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
|
||||
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -457,7 +475,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
function _update_plot_object(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
|
||||
+61
-41
@@ -2,6 +2,10 @@
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pgfplots.jl"))
|
||||
end
|
||||
|
||||
const _pgfplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend,
|
||||
@@ -23,7 +27,7 @@ const _pgfplots_attr = merge_with_base_supported([
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
:colorbar, :colorbar_title,
|
||||
:colorbar,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
@@ -43,6 +47,23 @@ const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :d
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::PGFPlotsBackend)
|
||||
"""
|
||||
Pkg.add("PGFPlots")
|
||||
Pkg.build("PGFPlots")
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::PGFPlotsBackend; kw...)
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
const _pgfplots_linestyles = KW(
|
||||
@@ -103,7 +124,7 @@ function pgf_framestyle(style::Symbol)
|
||||
return style
|
||||
else
|
||||
default_style = get(_pgf_framestyle_defaults, style, :axes)
|
||||
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
|
||||
warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
|
||||
default_style
|
||||
end
|
||||
end
|
||||
@@ -133,9 +154,9 @@ pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
|
||||
pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
|
||||
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
|
||||
|
||||
function pgf_fillstyle(plotattributes, i = 1)
|
||||
cstr,a = pgf_color(get_fillcolor(plotattributes, i))
|
||||
fa = get_fillalpha(plotattributes, i)
|
||||
function pgf_fillstyle(d, i = 1)
|
||||
cstr,a = pgf_color(get_fillcolor(d, i))
|
||||
fa = get_fillalpha(d, i)
|
||||
if fa != nothing
|
||||
a = fa
|
||||
end
|
||||
@@ -151,11 +172,11 @@ function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
|
||||
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
|
||||
end
|
||||
|
||||
function pgf_linestyle(plotattributes, i = 1)
|
||||
lw = pgf_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i)
|
||||
lc = get_linecolor(plotattributes, i)
|
||||
la = get_linealpha(plotattributes, i)
|
||||
ls = get_linestyle(plotattributes, i)
|
||||
function pgf_linestyle(d, i = 1)
|
||||
lw = pgf_thickness_scaling(d) * get_linewidth(d, i)
|
||||
lc = get_linecolor(d, i)
|
||||
la = get_linealpha(d, i)
|
||||
ls = get_linestyle(d, i)
|
||||
return pgf_linestyle(lw, lc, la, ls)
|
||||
end
|
||||
|
||||
@@ -164,19 +185,19 @@ function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
|
||||
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
|
||||
end
|
||||
|
||||
function pgf_marker(plotattributes, i = 1)
|
||||
shape = _cycle(plotattributes[:markershape], i)
|
||||
cstr, a = pgf_color(plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)))
|
||||
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)))
|
||||
function pgf_marker(d, i = 1)
|
||||
shape = _cycle(d[:markershape], i)
|
||||
cstr, a = pgf_color(plot_color(get_markercolor(d, i), get_markeralpha(d, i)))
|
||||
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(d, i), get_markerstrokealpha(d, i)))
|
||||
"""
|
||||
mark = $(get(_pgfplots_markers, shape, "*")),
|
||||
mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),
|
||||
mark size = $(pgf_thickness_scaling(d) * 0.5 * _cycle(d[:markersize], i)),
|
||||
mark options = {
|
||||
color = $cstr_stroke, draw opacity = $a_stroke,
|
||||
fill = $cstr, fill opacity = $a,
|
||||
line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)),
|
||||
line width = $(pgf_thickness_scaling(d) * _cycle(d[:markerstrokewidth], i)),
|
||||
rotate = $(shape == :dtriangle ? 180 : 0),
|
||||
$(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid"))
|
||||
$(get(_pgfplots_linestyles, _cycle(d[:markerstrokestyle], i), "solid"))
|
||||
}"""
|
||||
end
|
||||
|
||||
@@ -197,24 +218,24 @@ end
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function pgf_series(sp::Subplot, series::Series)
|
||||
plotattributes = series.plotattributes
|
||||
st = plotattributes[:seriestype]
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
series_collection = PGFPlots.Plot[]
|
||||
|
||||
# function args
|
||||
args = if st == :contour
|
||||
plotattributes[:z].surf, plotattributes[:x], plotattributes[:y]
|
||||
d[:z].surf, d[:x], d[:y]
|
||||
elseif is3d(st)
|
||||
plotattributes[:x], plotattributes[:y], plotattributes[:z]
|
||||
d[:x], d[:y], d[:z]
|
||||
elseif st == :straightline
|
||||
straightline_data(series)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
elseif ispolar(sp)
|
||||
theta, r = filter_radial_data(plotattributes[:x], plotattributes[:y], axis_limits(sp[:yaxis]))
|
||||
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
|
||||
rad2deg.(theta), r
|
||||
else
|
||||
plotattributes[:x], plotattributes[:y]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
# PGFPlots can't handle non-Vector?
|
||||
@@ -227,8 +248,8 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
if st in (:contour, :histogram2d)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(plotattributes))
|
||||
push!(style, pgf_marker(plotattributes))
|
||||
push!(style, pgf_linestyle(d))
|
||||
push!(style, pgf_marker(d))
|
||||
push!(style, "forget plot")
|
||||
|
||||
kw[:style] = join(style, ',')
|
||||
@@ -247,21 +268,21 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
for (i, rng) in enumerate(segments)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(plotattributes, i))
|
||||
push!(style, pgf_marker(plotattributes, i))
|
||||
push!(style, pgf_linestyle(d, i))
|
||||
push!(style, pgf_marker(d, i))
|
||||
|
||||
if st == :shape
|
||||
push!(style, pgf_fillstyle(plotattributes, i))
|
||||
push!(style, pgf_fillstyle(d, i))
|
||||
end
|
||||
|
||||
# add to legend?
|
||||
if i == 1 && sp[:legend] != :none && should_add_to_legend(series)
|
||||
if plotattributes[:fillrange] != nothing
|
||||
if d[:fillrange] != nothing
|
||||
push!(style, "forget plot")
|
||||
push!(series_collection, pgf_fill_legend_hack(plotattributes, args))
|
||||
push!(series_collection, pgf_fill_legend_hack(d, args))
|
||||
else
|
||||
kw[:legendentry] = plotattributes[:label]
|
||||
if st == :shape # || plotattributes[:fillrange] != nothing
|
||||
kw[:legendentry] = d[:label]
|
||||
if st == :shape # || d[:fillrange] != nothing
|
||||
push!(style, "area legend")
|
||||
end
|
||||
end
|
||||
@@ -328,16 +349,16 @@ function pgf_fillrange_args(fillrange, x, y, z)
|
||||
return x_fill, y_fill, z_fill
|
||||
end
|
||||
|
||||
function pgf_fill_legend_hack(plotattributes, args)
|
||||
function pgf_fill_legend_hack(d, args)
|
||||
style = []
|
||||
kw = KW()
|
||||
push!(style, pgf_linestyle(plotattributes, 1))
|
||||
push!(style, pgf_marker(plotattributes, 1))
|
||||
push!(style, pgf_fillstyle(plotattributes, 1))
|
||||
push!(style, pgf_linestyle(d, 1))
|
||||
push!(style, pgf_marker(d, 1))
|
||||
push!(style, pgf_fillstyle(d, 1))
|
||||
push!(style, "area legend")
|
||||
kw[:legendentry] = plotattributes[:label]
|
||||
kw[:legendentry] = d[:label]
|
||||
kw[:style] = join(style, ',')
|
||||
st = plotattributes[:seriestype]
|
||||
st = d[:seriestype]
|
||||
func = if st == :path3d
|
||||
PGFPlots.Linear3
|
||||
elseif st == :scatter
|
||||
@@ -535,8 +556,8 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
# colormap this should not cause any problem.
|
||||
for series in series_list(sp)
|
||||
for col in (:markercolor, :fillcolor, :linecolor)
|
||||
if typeof(series.plotattributes[col]) == ColorGradient
|
||||
push!(style,"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}")
|
||||
if typeof(series.d[col]) == ColorGradient
|
||||
push!(style,"colormap={plots}{$(pgf_colormap(series.d[col]))}")
|
||||
|
||||
if sp[:colorbar] == :none
|
||||
kw[:colorbar] = "false"
|
||||
@@ -550,7 +571,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
end
|
||||
@label colorbar_end
|
||||
|
||||
push!(style, "colorbar style={title=$(sp[:colorbar_title])}")
|
||||
o = axisf(; style = join(style, ","), kw...)
|
||||
|
||||
# add the series object to the PGFPlots.Axis
|
||||
|
||||
+175
-164
@@ -1,6 +1,10 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotly.jl"))
|
||||
end
|
||||
|
||||
const _plotly_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
@@ -64,7 +68,7 @@ function _plotly_framestyle(style::Symbol)
|
||||
return style
|
||||
else
|
||||
default_style = get(_plotly_framestyle_defaults, style, :axes)
|
||||
@warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
|
||||
warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
|
||||
default_style
|
||||
end
|
||||
end
|
||||
@@ -72,37 +76,46 @@ end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::PlotlyBackend)
|
||||
"""
|
||||
Pkg.build("Plots")
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
const _plotly_js_path = joinpath(dirname(@__FILE__), "..", "..", "deps", "plotly-latest.min.js")
|
||||
const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
|
||||
|
||||
_js_code = open(read, _plotly_js_path, "r")
|
||||
function _initialize_backend(::PlotlyBackend; kw...)
|
||||
@eval begin
|
||||
_js_code = open(readstring, _plotly_js_path, "r")
|
||||
|
||||
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
|
||||
_js_script = """
|
||||
<script type='text/javascript'>
|
||||
define('plotly', function(require, exports, module) {
|
||||
$(_js_code)
|
||||
});
|
||||
require(['plotly'], function(Plotly) {
|
||||
window.Plotly = Plotly;
|
||||
});
|
||||
</script>
|
||||
"""
|
||||
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
|
||||
_js_script = """
|
||||
<script type='text/javascript'>
|
||||
define('plotly', function(require, exports, module) {
|
||||
$(_js_code)
|
||||
});
|
||||
require(['plotly'], function(Plotly) {
|
||||
window.Plotly = Plotly;
|
||||
});
|
||||
</script>
|
||||
"""
|
||||
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
display("text/html", _js_script)
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
display("text/html", _js_script)
|
||||
end
|
||||
|
||||
# if isatom()
|
||||
# import Atom
|
||||
# Atom.@msg evaljs(_js_code)
|
||||
# end
|
||||
|
||||
end
|
||||
# TODO: other initialization
|
||||
end
|
||||
|
||||
# if isatom()
|
||||
# import Atom
|
||||
# Atom.@msg evaljs(_js_code)
|
||||
# end
|
||||
using UUIDs
|
||||
|
||||
push!(_initialized_backends, :plotly)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@@ -149,7 +162,7 @@ function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper"
|
||||
))
|
||||
end
|
||||
|
||||
# function get_annotation_dict_for_arrow(plotattributes::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
|
||||
# function get_annotation_dict_for_arrow(d::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
|
||||
# xdiff = xyprev[1] - xy[1]
|
||||
# ydiff = xyprev[2] - xy[2]
|
||||
# dist = sqrt(xdiff^2 + ydiff^2)
|
||||
@@ -163,7 +176,7 @@ end
|
||||
# # :ay => -40,
|
||||
# :ax => 10xdiff / dist,
|
||||
# :ay => -10ydiff / dist,
|
||||
# :arrowcolor => rgba_string(plotattributes[:linecolor]),
|
||||
# :arrowcolor => rgba_string(d[:linecolor]),
|
||||
# :xref => "x",
|
||||
# :yref => "y",
|
||||
# :arrowsize => 10a.headwidth,
|
||||
@@ -306,14 +319,14 @@ function plotly_polaraxis(axis::Axis)
|
||||
end
|
||||
|
||||
function plotly_layout(plt::Plot)
|
||||
plotattributes_out = KW()
|
||||
d_out = KW()
|
||||
|
||||
w, h = plt[:size]
|
||||
plotattributes_out[:width], plotattributes_out[:height] = w, h
|
||||
plotattributes_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
|
||||
plotattributes_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
|
||||
d_out[:width], d_out[:height] = w, h
|
||||
d_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
|
||||
d_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
|
||||
|
||||
plotattributes_out[:annotations] = KW[]
|
||||
d_out[:annotations] = KW[]
|
||||
|
||||
multiple_subplots = length(plt.subplots) > 1
|
||||
|
||||
@@ -334,10 +347,10 @@ function plotly_layout(plt::Plot)
|
||||
end
|
||||
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
|
||||
title_font = font(titlefont(sp), :top)
|
||||
push!(plotattributes_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
|
||||
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
|
||||
end
|
||||
|
||||
plotattributes_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
|
||||
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
|
||||
|
||||
# set to supported framestyle
|
||||
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
|
||||
@@ -346,7 +359,7 @@ function plotly_layout(plt::Plot)
|
||||
if is3d(sp)
|
||||
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
|
||||
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
|
||||
plotattributes_out[:scene] = KW(
|
||||
d_out[:scene] = KW(
|
||||
Symbol("xaxis$(spidx)") => plotly_axis(plt, sp[:xaxis], sp),
|
||||
Symbol("yaxis$(spidx)") => plotly_axis(plt, sp[:yaxis], sp),
|
||||
Symbol("zaxis$(spidx)") => plotly_axis(plt, sp[:zaxis], sp),
|
||||
@@ -361,19 +374,19 @@ function plotly_layout(plt::Plot)
|
||||
),
|
||||
)
|
||||
elseif ispolar(sp)
|
||||
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
|
||||
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
|
||||
d_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
|
||||
d_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
|
||||
else
|
||||
plotattributes_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
|
||||
d_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
|
||||
# don't allow yaxis to be reupdated/reanchored in a linked subplot
|
||||
spidx == y_idx ? plotattributes_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing
|
||||
spidx == y_idx ? d_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing
|
||||
end
|
||||
|
||||
# legend
|
||||
plotattributes_out[:showlegend] = sp[:legend] != :none
|
||||
d_out[:showlegend] = sp[:legend] != :none
|
||||
xpos,ypos = plotly_legend_pos(sp[:legend])
|
||||
if sp[:legend] != :none
|
||||
plotattributes_out[:legend] = KW(
|
||||
d_out[:legend] = KW(
|
||||
:bgcolor => rgba_string(sp[:background_color_legend]),
|
||||
:bordercolor => rgba_string(sp[:foreground_color_legend]),
|
||||
:font => plotly_font(legendfont(sp)),
|
||||
@@ -385,13 +398,13 @@ function plotly_layout(plt::Plot)
|
||||
|
||||
# annotations
|
||||
for ann in sp[:annotations]
|
||||
append!(plotattributes_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
|
||||
append!(d_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
|
||||
end
|
||||
# series_annotations
|
||||
for series in series_list(sp)
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
|
||||
push!(plotattributes_out[:annotations], plotly_annotation_dict(
|
||||
push!(d_out[:annotations], plotly_annotation_dict(
|
||||
xi,
|
||||
yi,
|
||||
PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)")
|
||||
@@ -404,24 +417,24 @@ function plotly_layout(plt::Plot)
|
||||
# a = sargs[:arrow]
|
||||
# if sargs[:seriestype] in (:path, :line) && typeof(a) <: Arrow
|
||||
# add_arrows(sargs[:x], sargs[:y]) do xyprev, xy
|
||||
# push!(plotattributes_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a))
|
||||
# push!(d_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a))
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
if ispolar(sp)
|
||||
plotattributes_out[:direction] = "counterclockwise"
|
||||
d_out[:direction] = "counterclockwise"
|
||||
end
|
||||
|
||||
plotattributes_out
|
||||
d_out
|
||||
end
|
||||
|
||||
# turn off hover if nothing's using it
|
||||
if all(series -> series.plotattributes[:hover] in (false,:none), plt.series_list)
|
||||
plotattributes_out[:hovermode] = "none"
|
||||
if all(series -> series.d[:hover] in (false,:none), plt.series_list)
|
||||
d_out[:hovermode] = "none"
|
||||
end
|
||||
|
||||
plotattributes_out
|
||||
d_out
|
||||
end
|
||||
|
||||
function plotly_layout_json(plt::Plot)
|
||||
@@ -527,24 +540,21 @@ end
|
||||
as_gradient(grad::ColorGradient, α) = grad
|
||||
as_gradient(grad, α) = cgrad(alpha = α)
|
||||
|
||||
# get a dictionary representing the series params (plotattributes is the Plots-dict, plotattributes_out is the Plotly-dict)
|
||||
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
|
||||
function plotly_series(plt::Plot, series::Series)
|
||||
st = series[:seriestype]
|
||||
|
||||
sp = series[:subplot]
|
||||
clims = get_clims(sp)
|
||||
|
||||
if st == :shape
|
||||
return plotly_series_shapes(plt, series, clims)
|
||||
return plotly_series_shapes(plt, series)
|
||||
end
|
||||
|
||||
plotattributes_out = KW()
|
||||
sp = series[:subplot]
|
||||
d_out = KW()
|
||||
|
||||
# these are the axes that the series should be mapped to
|
||||
x_idx, y_idx = plotly_link_indicies(plt, sp)
|
||||
plotattributes_out[:xaxis] = "x$(x_idx)"
|
||||
plotattributes_out[:yaxis] = "y$(y_idx)"
|
||||
plotattributes_out[:showlegend] = should_add_to_legend(series)
|
||||
d_out[:xaxis] = "x$(x_idx)"
|
||||
d_out[:yaxis] = "y$(y_idx)"
|
||||
d_out[:showlegend] = should_add_to_legend(series)
|
||||
|
||||
if st == :straightline
|
||||
x, y = straightline_data(series)
|
||||
@@ -557,7 +567,7 @@ function plotly_series(plt::Plot, series::Series)
|
||||
for (letter, data) in zip((:x, :y, :z), (x, y, z))
|
||||
)
|
||||
|
||||
plotattributes_out[:name] = series[:label]
|
||||
d_out[:name] = series[:label]
|
||||
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || series[:markershape] != :none
|
||||
@@ -565,69 +575,70 @@ function plotly_series(plt::Plot, series::Series)
|
||||
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
|
||||
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
|
||||
|
||||
plotattributes_out[:colorbar] = KW(:title => sp[:colorbar_title])
|
||||
d_out[:colorbar] = KW(:title => sp[:colorbar_title])
|
||||
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
plotattributes_out[:zmin], plotattributes_out[:zmax] = clims
|
||||
d_out[:zmin], d_out[:zmax] = clims
|
||||
end
|
||||
|
||||
# set the "type"
|
||||
if st in (:path, :scatter, :scattergl, :straightline, :path3d, :scatter3d)
|
||||
return plotly_series_segments(series, plotattributes, x, y, z, clims)
|
||||
return plotly_series_segments(series, d_out, x, y, z)
|
||||
|
||||
elseif st == :heatmap
|
||||
x = heatmap_edges(x, sp[:xaxis][:scale])
|
||||
y = heatmap_edges(y, sp[:yaxis][:scale])
|
||||
plotattributes_out[:type] = "heatmap"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
d_out[:type] = "heatmap"
|
||||
d_out[:x], d_out[:y], d_out[:z] = x, y, z
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:showscale] = hascolorbar(sp)
|
||||
|
||||
elseif st == :contour
|
||||
plotattributes_out[:type] = "contour"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
# plotattributes_out[:showscale] = series[:colorbar] != :none
|
||||
plotattributes_out[:ncontours] = series[:levels]
|
||||
plotattributes_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
d_out[:type] = "contour"
|
||||
d_out[:x], d_out[:y], d_out[:z] = x, y, z
|
||||
# d_out[:showscale] = series[:colorbar] != :none
|
||||
d_out[:ncontours] = series[:levels]
|
||||
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
|
||||
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
d_out[:showscale] = hascolorbar(sp)
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
plotattributes_out[:type] = "surface"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
d_out[:type] = "surface"
|
||||
d_out[:x], d_out[:y], d_out[:z] = x, y, z
|
||||
if st == :wireframe
|
||||
plotattributes_out[:hidesurface] = true
|
||||
d_out[:hidesurface] = true
|
||||
wirelines = KW(
|
||||
:show => true,
|
||||
:color => rgba_string(plot_color(series[:linecolor], series[:linealpha])),
|
||||
:highlightwidth => series[:linewidth],
|
||||
)
|
||||
plotattributes_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
|
||||
plotattributes_out[:showscale] = false
|
||||
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
|
||||
d_out[:showscale] = false
|
||||
else
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
plotattributes_out[:opacity] = series[:fillalpha]
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:opacity] = series[:fillalpha]
|
||||
if series[:fill_z] != nothing
|
||||
plotattributes_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
|
||||
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
|
||||
end
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
d_out[:showscale] = hascolorbar(sp)
|
||||
end
|
||||
|
||||
elseif st == :pie
|
||||
plotattributes_out[:type] = "pie"
|
||||
plotattributes_out[:labels] = pie_labels(sp, series)
|
||||
plotattributes_out[:values] = y
|
||||
plotattributes_out[:hoverinfo] = "label+percent+name"
|
||||
d_out[:type] = "pie"
|
||||
d_out[:labels] = pie_labels(sp, series)
|
||||
d_out[:values] = y
|
||||
d_out[:hoverinfo] = "label+percent+name"
|
||||
|
||||
else
|
||||
@warn("Plotly: seriestype $st isn't supported.")
|
||||
warn("Plotly: seriestype $st isn't supported.")
|
||||
return KW()
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
inds = eachindex(x)
|
||||
plotattributes_out[:marker] = KW(
|
||||
d_out[:marker] = KW(
|
||||
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
|
||||
# :opacity => series[:markeralpha],
|
||||
:size => 2 * _cycle(series[:markersize], inds),
|
||||
@@ -639,22 +650,22 @@ function plotly_series(plt::Plot, series::Series)
|
||||
)
|
||||
end
|
||||
|
||||
plotly_polar!(plotattributes_out, series)
|
||||
plotly_hover!(plotattributes_out, series[:hover])
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, series[:hover])
|
||||
|
||||
return [plotattributes_out]
|
||||
return [d_out]
|
||||
end
|
||||
|
||||
function plotly_series_shapes(plt::Plot, series::Series, clims)
|
||||
function plotly_series_shapes(plt::Plot, series::Series)
|
||||
segments = iter_segments(series)
|
||||
plotattributes_outs = Vector{KW}(undef, length(segments))
|
||||
d_outs = Vector{KW}(length(segments))
|
||||
|
||||
# TODO: create a plotattributes_out for each polygon
|
||||
# TODO: create a d_out for each polygon
|
||||
# x, y = series[:x], series[:y]
|
||||
|
||||
# these are the axes that the series should be mapped to
|
||||
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
|
||||
plotattributes_base = KW(
|
||||
d_base = KW(
|
||||
:xaxis => "x$(x_idx)",
|
||||
:yaxis => "y$(y_idx)",
|
||||
:name => series[:label],
|
||||
@@ -669,37 +680,37 @@ function plotly_series_shapes(plt::Plot, series::Series, clims)
|
||||
length(rng) < 2 && continue
|
||||
|
||||
# to draw polygons, we actually draw lines with fill
|
||||
plotattributes_out = merge(plotattributes_base, KW(
|
||||
d_out = merge(d_base, KW(
|
||||
:type => "scatter",
|
||||
:mode => "lines",
|
||||
:x => vcat(x[rng], x[rng[1]]),
|
||||
:y => vcat(y[rng], y[rng[1]]),
|
||||
:fill => "tozeroy",
|
||||
:fillcolor => rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))),
|
||||
:fillcolor => rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i))),
|
||||
))
|
||||
if series[:markerstrokewidth] > 0
|
||||
plotattributes[:line] = KW(
|
||||
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
|
||||
d_out[:line] = KW(
|
||||
:color => rgba_string(plot_color(get_linecolor(series, i), get_linealpha(series, i))),
|
||||
:width => get_linewidth(series, i),
|
||||
:dash => string(get_linestyle(series, i)),
|
||||
)
|
||||
end
|
||||
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
plotly_polar!(plotattributes_out, series)
|
||||
plotly_hover!(plotattributes_out, _cycle(series[:hover], i))
|
||||
plotattributes_outs[i] = plotattributes_out
|
||||
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, _cycle(series[:hover], i))
|
||||
d_outs[i] = d_out
|
||||
end
|
||||
if series[:fill_z] != nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
|
||||
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
|
||||
elseif series[:line_z] != nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
|
||||
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
|
||||
elseif series[:marker_z] != nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
|
||||
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
|
||||
end
|
||||
plotattributes_outs
|
||||
d_outs
|
||||
end
|
||||
|
||||
function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z, clims)
|
||||
function plotly_series_segments(series::Series, d_base::KW, x, y, z)
|
||||
st = series[:seriestype]
|
||||
sp = series[:subplot]
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
@@ -709,51 +720,51 @@ function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z,
|
||||
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
|
||||
|
||||
segments = iter_segments(series)
|
||||
plotattributes_outs = Vector{KW}(undef, (hasfillrange ? 2 : 1 ) * length(segments))
|
||||
d_outs = Vector{KW}((hasfillrange ? 2 : 1 ) * length(segments))
|
||||
|
||||
for (i,rng) in enumerate(segments)
|
||||
!isscatter && length(rng) < 2 && continue
|
||||
|
||||
plotattributes_out = deepcopy(plotattributes_base)
|
||||
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
plotattributes_out[:legendgroup] = series[:label]
|
||||
d_out = deepcopy(d_base)
|
||||
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
d_out[:legendgroup] = series[:label]
|
||||
|
||||
# set the type
|
||||
if st in (:path, :scatter, :scattergl, :straightline)
|
||||
plotattributes_out[:type] = st==:scattergl ? "scattergl" : "scatter"
|
||||
plotattributes_out[:mode] = if hasmarker
|
||||
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
|
||||
d_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
|
||||
plotattributes[:fill] = "tozeroy"
|
||||
plotattributes[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
|
||||
d_out[:fill] = "tozeroy"
|
||||
d_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i)))
|
||||
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
|
||||
plotattributes[:fill] = "tonexty"
|
||||
plotattributes[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
|
||||
d_out[:fill] = "tonexty"
|
||||
d_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i)))
|
||||
elseif !(series[:fillrange] in (false, nothing))
|
||||
@warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
|
||||
warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
|
||||
end
|
||||
plotattributes_out[:x], plotattributes_out[:y] = x[rng], y[rng]
|
||||
d_out[:x], d_out[:y] = x[rng], y[rng]
|
||||
|
||||
elseif st in (:path3d, :scatter3d)
|
||||
plotattributes_out[:type] = "scatter3d"
|
||||
plotattributes_out[:mode] = if hasmarker
|
||||
d_out[:type] = "scatter3d"
|
||||
d_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x[rng], y[rng], z[rng]
|
||||
d_out[:x], d_out[:y], d_out[:z] = x[rng], y[rng], z[rng]
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
plotattributes_out[:marker] = KW(
|
||||
d_out[:marker] = KW(
|
||||
:symbol => get(_plotly_markers, _cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
|
||||
# :opacity => series[:markeralpha],
|
||||
:size => 2 * _cycle(series[:markersize], i),
|
||||
:color => rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))),
|
||||
:color => rgba_string(plot_color(get_markercolor(series, i), get_markeralpha(series, i))),
|
||||
:line => KW(
|
||||
:color => rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))),
|
||||
:width => _cycle(series[:markerstrokewidth], i),
|
||||
@@ -763,8 +774,8 @@ function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z,
|
||||
|
||||
# add "line"
|
||||
if hasline
|
||||
plotattributes[:line] = KW(
|
||||
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
|
||||
d_out[:line] = KW(
|
||||
:color => rgba_string(plot_color(get_linecolor(series, i), get_linealpha(series, i))),
|
||||
:width => get_linewidth(series, i),
|
||||
:shape => if st == :steppre
|
||||
"vh"
|
||||
@@ -777,14 +788,14 @@ function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z,
|
||||
)
|
||||
end
|
||||
|
||||
plotly_polar!(plotattributes_out, series)
|
||||
plotly_hover!(plotattributes_out, _cycle(series[:hover], rng))
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, _cycle(series[:hover], rng))
|
||||
|
||||
if hasfillrange
|
||||
# if hasfillrange is true, return two dictionaries (one for original
|
||||
# series, one for series being filled to) instead of one
|
||||
plotattributes_out_fillrange = deepcopy(plotattributes_out)
|
||||
plotattributes_out_fillrange[:showlegend] = false
|
||||
d_out_fillrange = deepcopy(d_out)
|
||||
d_out_fillrange[:showlegend] = false
|
||||
# if fillrange is provided as real or tuple of real, expand to array
|
||||
if typeof(series[:fillrange]) <: Real
|
||||
series[:fillrange] = fill(series[:fillrange], length(rng))
|
||||
@@ -794,49 +805,49 @@ function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z,
|
||||
series[:fillrange] = (f1, f2)
|
||||
end
|
||||
if isa(series[:fillrange], AbstractVector)
|
||||
plotattributes_out_fillrange[:y] = series[:fillrange][rng]
|
||||
delete!(plotattributes_out_fillrange, :fill)
|
||||
delete!(plotattributes_out_fillrange, :fillcolor)
|
||||
d_out_fillrange[:y] = series[:fillrange][rng]
|
||||
delete!(d_out_fillrange, :fill)
|
||||
delete!(d_out_fillrange, :fillcolor)
|
||||
else
|
||||
# if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange
|
||||
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
|
||||
# is the series that will do the filling
|
||||
fillrng = Tuple(series[:fillrange][i][rng] for i in 1:2)
|
||||
plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
|
||||
plotattributes_out_fillrange[:line][:width] = 0
|
||||
delete!(plotattributes_out, :fill)
|
||||
delete!(plotattributes_out, :fillcolor)
|
||||
d_out_fillrange[:x], d_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
|
||||
d_out_fillrange[:line][:width] = 0
|
||||
delete!(d_out, :fill)
|
||||
delete!(d_out, :fillcolor)
|
||||
end
|
||||
|
||||
plotattributes_outs[(2 * i - 1):(2 * i)] = [plotattributes_out_fillrange, plotattributes_out]
|
||||
d_outs[(2 * i - 1):(2 * i)] = [d_out_fillrange, d_out]
|
||||
else
|
||||
plotattributes_outs[i] = plotattributes_out
|
||||
d_outs[i] = d_out
|
||||
end
|
||||
end
|
||||
|
||||
if series[:line_z] != nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
|
||||
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
|
||||
elseif series[:fill_z] != nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
|
||||
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
|
||||
elseif series[:marker_z] != nothing
|
||||
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
|
||||
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
|
||||
end
|
||||
|
||||
plotattributes_outs
|
||||
d_outs
|
||||
end
|
||||
|
||||
function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symbol)
|
||||
plotattributes_out = deepcopy(plotattributes_base)
|
||||
function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
|
||||
d_out = deepcopy(d_base)
|
||||
cmin, cmax = get_clims(series[:subplot])
|
||||
plotattributes_out[:showlegend] = false
|
||||
plotattributes_out[:type] = is3d(series) ? :scatter3d : :scatter
|
||||
plotattributes_out[:hoverinfo] = :none
|
||||
plotattributes_out[:mode] = :markers
|
||||
plotattributes_out[:x], plotattributes_out[:y] = [series[:x][1]], [series[:y][1]]
|
||||
d_out[:showlegend] = false
|
||||
d_out[:type] = is3d(series) ? :scatter3d : :scatter
|
||||
d_out[:hoverinfo] = :none
|
||||
d_out[:mode] = :markers
|
||||
d_out[:x], d_out[:y] = [series[:x][1]], [series[:y][1]]
|
||||
if is3d(series)
|
||||
plotattributes_out[:z] = [series[:z][1]]
|
||||
d_out[:z] = [series[:z][1]]
|
||||
end
|
||||
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
|
||||
plotattributes_out[:marker] = KW(
|
||||
d_out[:marker] = KW(
|
||||
:size => 0,
|
||||
:opacity => 0,
|
||||
:color => [0.5],
|
||||
@@ -845,26 +856,26 @@ function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symb
|
||||
:colorscale => plotly_colorscale(series[Symbol("$(sym)color")], 1),
|
||||
:showscale => hascolorbar(series[:subplot]),
|
||||
)
|
||||
return plotattributes_out
|
||||
return d_out
|
||||
end
|
||||
|
||||
|
||||
function plotly_polar!(plotattributes_out::KW, series::Series)
|
||||
function plotly_polar!(d_out::KW, series::Series)
|
||||
# convert polar plots x/y to theta/radius
|
||||
if ispolar(series[:subplot])
|
||||
theta, r = filter_radial_data(pop!(plotattributes_out, :x), pop!(plotattributes_out, :y), axis_limits(series[:subplot][:yaxis]))
|
||||
plotattributes_out[:t] = rad2deg.(theta)
|
||||
plotattributes_out[:r] = r
|
||||
theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
|
||||
d_out[:t] = rad2deg.(theta)
|
||||
d_out[:r] = r
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_hover!(plotattributes_out::KW, hover)
|
||||
function plotly_hover!(d_out::KW, hover)
|
||||
# hover text
|
||||
if hover in (:none, false)
|
||||
plotattributes_out[:hoverinfo] = "none"
|
||||
d_out[:hoverinfo] = "none"
|
||||
elseif hover != nothing
|
||||
plotattributes_out[:hoverinfo] = "text"
|
||||
plotattributes_out[:text] = hover
|
||||
d_out[:hoverinfo] = "text"
|
||||
d_out[:text] = hover
|
||||
end
|
||||
end
|
||||
|
||||
@@ -895,7 +906,7 @@ function html_body(plt::Plot{PlotlyBackend}, style = nothing)
|
||||
w, h = plt[:size]
|
||||
style = "width:$(w)px;height:$(h)px;"
|
||||
end
|
||||
uuid = UUIDs.uuid4()
|
||||
uuid = Base.Random.uuid4()
|
||||
html = """
|
||||
<div id=\"$(uuid)\" style=\"$(style)\"></div>
|
||||
<script>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
|
||||
end
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
|
||||
@@ -10,6 +13,35 @@ const _plotlyjs_scale = _plotly_scale
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function add_backend_string(::PlotlyJSBackend)
|
||||
"""
|
||||
if !Plots.is_installed("PlotlyJS")
|
||||
Pkg.add("PlotlyJS")
|
||||
end
|
||||
if !Plots.is_installed("Rsvg")
|
||||
Pkg.add("Rsvg")
|
||||
end
|
||||
import Blink
|
||||
Blink.AtomShell.install()
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
function _initialize_backend(::PlotlyJSBackend; kw...)
|
||||
@eval begin
|
||||
import PlotlyJS
|
||||
export PlotlyJS
|
||||
end
|
||||
|
||||
# # override IJulia inline display
|
||||
# if isijulia()
|
||||
# IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
|
||||
# end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
|
||||
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
|
||||
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
|
||||
@@ -31,14 +63,14 @@ end
|
||||
|
||||
function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
|
||||
xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y))
|
||||
kw = KW(xsym => (series.plotattributes[:x],), ysym => (series.plotattributes[:y],))
|
||||
kw = KW(xsym => (series.d[:x],), ysym => (series.d[:y],))
|
||||
z = series[:z]
|
||||
if z != nothing
|
||||
kw[:z] = (isa(z,Surface) ? transpose_z(series, series[:z].surf, false) : z,)
|
||||
end
|
||||
PlotlyJS.restyle!(
|
||||
plt.o,
|
||||
findfirst(isequal(series), plt.series_list),
|
||||
findfirst(plt.series_list, series),
|
||||
kw
|
||||
)
|
||||
end
|
||||
|
||||
+129
-101
@@ -1,6 +1,10 @@
|
||||
|
||||
# https://github.com/stevengj/PyPlot.jl
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pyplot.jl"))
|
||||
end
|
||||
|
||||
const _pyplot_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
@@ -55,31 +59,57 @@ is_marker_supported(::PyPlotBackend, shape::Shape) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
# problem: https://github.com/tbreloff/Plots.jl/issues/308
|
||||
# solution: hack from @stevengj: https://github.com/stevengj/PyPlot.jl/pull/223#issuecomment-229747768
|
||||
otherdisplays = splice!(Base.Multimedia.displays, 2:length(Base.Multimedia.displays))
|
||||
append!(Base.Multimedia.displays, otherdisplays)
|
||||
pycolors = PyPlot.pyimport("matplotlib.colors")
|
||||
pypath = PyPlot.pyimport("matplotlib.path")
|
||||
mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
|
||||
pypatches = PyPlot.pyimport("matplotlib.patches")
|
||||
pyfont = PyPlot.pyimport("matplotlib.font_manager")
|
||||
pyticker = PyPlot.pyimport("matplotlib.ticker")
|
||||
pycmap = PyPlot.pyimport("matplotlib.cm")
|
||||
pynp = PyPlot.pyimport("numpy")
|
||||
pynp["seterr"](invalid="ignore")
|
||||
pytransforms = PyPlot.pyimport("matplotlib.transforms")
|
||||
pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
pyart3d = PyPlot.art3D
|
||||
function add_backend_string(::PyPlotBackend)
|
||||
"""
|
||||
if !Plots.is_installed("PyPlot")
|
||||
Pkg.add("PyPlot")
|
||||
end
|
||||
withenv("PYTHON" => "") do
|
||||
Pkg.build("PyPlot")
|
||||
end
|
||||
|
||||
# "support" matplotlib v1.5
|
||||
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
|
||||
# now restart julia!
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::PyPlotBackend)
|
||||
@eval begin
|
||||
# problem: https://github.com/tbreloff/Plots.jl/issues/308
|
||||
# solution: hack from @stevengj: https://github.com/stevengj/PyPlot.jl/pull/223#issuecomment-229747768
|
||||
otherdisplays = splice!(Base.Multimedia.displays, 2:length(Base.Multimedia.displays))
|
||||
import PyPlot, PyCall
|
||||
import LaTeXStrings: latexstring
|
||||
append!(Base.Multimedia.displays, otherdisplays)
|
||||
|
||||
export PyPlot
|
||||
pycolors = PyPlot.pyimport("matplotlib.colors")
|
||||
pypath = PyPlot.pyimport("matplotlib.path")
|
||||
mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
|
||||
pypatches = PyPlot.pyimport("matplotlib.patches")
|
||||
pyfont = PyPlot.pyimport("matplotlib.font_manager")
|
||||
pyticker = PyPlot.pyimport("matplotlib.ticker")
|
||||
pycmap = PyPlot.pyimport("matplotlib.cm")
|
||||
pynp = PyPlot.pyimport("numpy")
|
||||
pynp["seterr"](invalid="ignore")
|
||||
pytransforms = PyPlot.pyimport("matplotlib.transforms")
|
||||
pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
pyart3d = PyPlot.art3D
|
||||
|
||||
# "support" matplotlib v1.5
|
||||
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()
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
# # convert colorant to 4-tuple RGBA
|
||||
# py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
|
||||
@@ -130,7 +160,7 @@ function py_linestyle(seriestype::Symbol, linestyle::Symbol)
|
||||
linestyle == :dash && return "--"
|
||||
linestyle == :dot && return ":"
|
||||
linestyle == :dashdot && return "-."
|
||||
@warn("Unknown linestyle $linestyle")
|
||||
warn("Unknown linestyle $linestyle")
|
||||
return "-"
|
||||
end
|
||||
|
||||
@@ -191,13 +221,13 @@ function py_marker(marker::Symbol)
|
||||
marker == :vline && return "|"
|
||||
haskey(_shapes, marker) && return py_marker(_shapes[marker])
|
||||
|
||||
@warn("Unknown marker $marker")
|
||||
warn("Unknown marker $marker")
|
||||
return "o"
|
||||
end
|
||||
|
||||
# py_marker(markers::AVec) = map(py_marker, markers)
|
||||
function py_marker(markers::AVec)
|
||||
@warn("Vectors of markers are currently unsupported in PyPlot: $markers")
|
||||
warn("Vectors of markers are currently unsupported in PyPlot: $markers")
|
||||
py_marker(markers[1])
|
||||
end
|
||||
|
||||
@@ -236,26 +266,23 @@ function add_pyfixedformatter(cbar, vals::AVec)
|
||||
cbar[:update_ticks]()
|
||||
end
|
||||
|
||||
@require LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" begin
|
||||
function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
if scale == :log10
|
||||
x -> LaTeXStrings.latexstring("10^{$x}")
|
||||
elseif scale == :log2
|
||||
x -> LaTeXStrings.latexstring("2^{$x}")
|
||||
elseif scale == :ln
|
||||
x -> LaTeXStrings.latexstring("e^{$x}")
|
||||
else
|
||||
string
|
||||
end
|
||||
|
||||
function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
if scale == :log10
|
||||
x -> latexstring("10^{$x}")
|
||||
elseif scale == :log2
|
||||
x -> latexstring("2^{$x}")
|
||||
elseif scale == :ln
|
||||
x -> latexstring("e^{$x}")
|
||||
else
|
||||
string
|
||||
end
|
||||
end
|
||||
|
||||
@require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" begin
|
||||
function py_mask_nans(z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
function py_mask_nans(z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -263,7 +290,7 @@ end
|
||||
function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
|
||||
x, y = series[:x], series[:y]
|
||||
nx, ny = length(x), length(y)
|
||||
if !isa(get(series.plotattributes, :z, nothing), Surface) && nx != ny
|
||||
if !isa(get(series.d, :z, nothing), Surface) && nx != ny
|
||||
if nx < ny
|
||||
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
else
|
||||
@@ -299,7 +326,7 @@ py_fillcolormap(series::Series) = py_colormap(series[:fillcolor])
|
||||
# getAxis(sp::Subplot) = sp.o
|
||||
|
||||
# function getAxis(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# sp = get_subplot(plt, get(series.plotattributes, :subplot, 1))
|
||||
# sp = get_subplot(plt, get(series.d, :subplot, 1))
|
||||
# getAxis(sp)
|
||||
# end
|
||||
|
||||
@@ -367,8 +394,8 @@ function py_bbox_title(ax)
|
||||
bb
|
||||
end
|
||||
|
||||
function py_thickness_scale(plt::Plot{PyPlotBackend}, ptsz)
|
||||
ptsz * plt[:thickness_scaling]
|
||||
function py_dpi_scale(plt::Plot{PyPlotBackend}, ptsz)
|
||||
ptsz
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -412,12 +439,12 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
# function _series_added(pkg::PyPlotBackend, plt::Plot, plotattributes::KW)
|
||||
# function _series_added(pkg::PyPlotBackend, plt::Plot, d::KW)
|
||||
# TODO: change this to accept Subplot??
|
||||
# function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# plotattributes = series.plotattributes
|
||||
# d = series.d
|
||||
st = series[:seriestype]
|
||||
sp = series[:subplot]
|
||||
ax = sp.o
|
||||
@@ -436,10 +463,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
# handle zcolor and get c/cmap
|
||||
needs_colorbar = hascolorbar(sp)
|
||||
vmin, vmax = clims = get_clims(sp)
|
||||
|
||||
# Dict to store extra kwargs
|
||||
extrakw = KW(:vmin => vmin, :vmax => vmax)
|
||||
extrakw = if needs_colorbar || is_2tuple(sp[:clims])
|
||||
vmin, vmax = get_clims(sp)
|
||||
KW(:vmin => vmin, :vmax => vmax)
|
||||
else
|
||||
KW()
|
||||
end
|
||||
|
||||
# holds references to any python object representing the matplotlib series
|
||||
handles = []
|
||||
@@ -476,7 +505,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# :label => series[:label],
|
||||
# :zorder => plt.n,
|
||||
# :cmap => py_linecolormap(series),
|
||||
# :linewidths => py_thickness_scale(plt, get_linewidth.(series, 1:n)),
|
||||
# :linewidths => py_dpi_scale(plt, get_linewidth.(series, 1:n)),
|
||||
# :linestyle => py_linestyle(st, get_linestyle.(series)),
|
||||
# :norm => pycolors["Normalize"](; extrakw...)
|
||||
# )
|
||||
@@ -500,8 +529,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[:plot]((arg[rng] for arg in xyargs)...;
|
||||
label = i == 1 ? series[:label] : "",
|
||||
zorder = series[:series_plotindex],
|
||||
color = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
|
||||
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
|
||||
color = py_color(get_linecolor(series, i), get_linealpha(series, i)),
|
||||
linewidth = py_dpi_scale(plt, get_linewidth(series, i)),
|
||||
linestyle = py_linestyle(st, get_linestyle(series, i)),
|
||||
solid_capstyle = "round",
|
||||
drawstyle = py_stepstyle(st)
|
||||
@@ -513,7 +542,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
a = series[:arrow]
|
||||
if a != nothing && !is3d(st) # TODO: handle 3d later
|
||||
if typeof(a) != Arrow
|
||||
@warn("Unexpected type for arrow: $(typeof(a))")
|
||||
warn("Unexpected type for arrow: $(typeof(a))")
|
||||
else
|
||||
arrowprops = KW(
|
||||
:arrowstyle => "simple,head_length=$(a.headlength),head_width=$(a.headwidth)",
|
||||
@@ -521,7 +550,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
:shrinkB => 0,
|
||||
:edgecolor => py_linecolor(series),
|
||||
:facecolor => py_linecolor(series),
|
||||
:linewidth => py_thickness_scale(plt, get_linewidth(series)),
|
||||
:linewidth => py_dpi_scale(plt, get_linewidth(series)),
|
||||
:linestyle => py_linestyle(st, get_linestyle(series)),
|
||||
)
|
||||
add_arrows(x, y) do xyprev, xy
|
||||
@@ -542,8 +571,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
:scatter3d, :steppre, :steppost,
|
||||
:bar)
|
||||
markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] != nothing
|
||||
# py_color(plot_color.(get_markercolor.(series, clims, eachindex(x)), get_markeralpha.(series, eachindex(x))))
|
||||
[py_color(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))) for i in eachindex(x)]
|
||||
py_color(plot_color.(get_markercolor.(series, eachindex(x)), get_markeralpha.(series, eachindex(x))))
|
||||
else
|
||||
py_color(plot_color(series[:markercolor], series[:markeralpha]))
|
||||
end
|
||||
@@ -561,7 +589,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
x,y = xyargs
|
||||
shapes = series[:markershape]
|
||||
msc = py_markerstrokecolor(series)
|
||||
lw = py_thickness_scale(plt, series[:markerstrokewidth])
|
||||
lw = py_dpi_scale(plt, series[:markerstrokewidth])
|
||||
for i=1:length(y)
|
||||
extrakw[:c] = _cycle(markercolor, i)
|
||||
|
||||
@@ -569,7 +597,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = py_marker(_cycle(shapes,i)),
|
||||
s = py_thickness_scale(plt, _cycle(series[:markersize],i) .^ 2),
|
||||
s = py_dpi_scale(plt, _cycle(series[:markersize],i) .^ 2),
|
||||
edgecolors = msc,
|
||||
linewidths = lw,
|
||||
extrakw...
|
||||
@@ -582,9 +610,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = py_marker(series[:markershape]),
|
||||
s = py_thickness_scale(plt, series[:markersize] .^ 2),
|
||||
s = py_dpi_scale(plt, series[:markersize] .^ 2),
|
||||
edgecolors = py_markerstrokecolor(series),
|
||||
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
|
||||
linewidths = py_dpi_scale(plt, series[:markerstrokewidth]),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -596,7 +624,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
gridsize = series[:bins],
|
||||
linewidths = py_thickness_scale(plt, series[:linewidth]),
|
||||
linewidths = py_dpi_scale(plt, series[:linewidth]),
|
||||
edgecolors = py_linecolor(series),
|
||||
cmap = py_fillcolormap(series), # applies to the pcolorfast object
|
||||
extrakw...
|
||||
@@ -627,7 +655,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[:contour](x, y, z, levelargs...;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
linewidths = py_thickness_scale(plt, series[:linewidth]),
|
||||
linewidths = py_dpi_scale(plt, series[:linewidth]),
|
||||
linestyles = py_linestyle(st, series[:linestyle]),
|
||||
extrakw...
|
||||
)
|
||||
@@ -669,7 +697,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
zorder = series[:series_plotindex],
|
||||
rstride = series[:stride][1],
|
||||
cstride = series[:stride][2],
|
||||
linewidth = py_thickness_scale(plt, series[:linewidth]),
|
||||
linewidth = py_dpi_scale(plt, series[:linewidth]),
|
||||
edgecolor = py_linecolor(series),
|
||||
extrakw...
|
||||
)
|
||||
@@ -691,11 +719,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
elseif typeof(z) <: AbstractVector
|
||||
# tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
handle = ax[:plot_trisurf](x, y, z;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
cmap = py_fillcolormap(series),
|
||||
linewidth = py_thickness_scale(plt, series[:linewidth]),
|
||||
linewidth = py_dpi_scale(plt, series[:linewidth]),
|
||||
edgecolor = py_linecolor(series),
|
||||
extrakw...
|
||||
)
|
||||
@@ -761,9 +794,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
path;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
edgecolor = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
|
||||
facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
|
||||
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
|
||||
edgecolor = py_color(get_linecolor(series, i), get_linealpha(series, i)),
|
||||
facecolor = py_color(get_fillcolor(series, i), get_fillalpha(series, i)),
|
||||
linewidth = py_dpi_scale(plt, get_linewidth(series, i)),
|
||||
linestyle = py_linestyle(st, get_linestyle(series, i)),
|
||||
fill = true
|
||||
)
|
||||
@@ -811,7 +844,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
|
||||
zorder = series[:series_plotindex],
|
||||
facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
|
||||
facecolor = py_color(get_fillcolor(series, i), get_fillalpha(series, i)),
|
||||
linewidths = 0
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -862,7 +895,7 @@ function py_compute_axis_minval(axis::Axis)
|
||||
sps = axis.sps
|
||||
for sp in sps
|
||||
for series in series_list(sp)
|
||||
v = series.plotattributes[axis[:letter]]
|
||||
v = series.d[axis[:letter]]
|
||||
if !isempty(v)
|
||||
minval = NaNMath.min(minval, ignorenan_minimum(abs.(v)))
|
||||
end
|
||||
@@ -879,7 +912,7 @@ end
|
||||
function py_set_scale(ax, axis::Axis)
|
||||
scale = axis[:scale]
|
||||
letter = axis[:letter]
|
||||
scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale")
|
||||
scale in supported_scales() || return warn("Unhandled scale value in pyplot: $scale")
|
||||
func = ax[Symbol("set_", letter, "scale")]
|
||||
kw = KW()
|
||||
arg = if scale == :identity
|
||||
@@ -922,8 +955,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
w, h = plt[:size]
|
||||
fig = plt.o
|
||||
fig[:clear]()
|
||||
dpi = plt[:dpi]
|
||||
fig[:set_size_inches](w/DPI, h/DPI, forward = true)
|
||||
dpi = plt[:thickness_scaling] * plt[:dpi]
|
||||
fig[:set_size_inches](w/DPI/plt[:thickness_scaling], h/DPI/plt[:thickness_scaling], forward = true)
|
||||
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
|
||||
fig[:set_dpi](plt[:dpi])
|
||||
|
||||
@@ -963,7 +996,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
:title
|
||||
end
|
||||
ax[func][:set_text](sp[:title])
|
||||
ax[func][:set_fontsize](py_thickness_scale(plt, sp[:titlefontsize]))
|
||||
ax[func][:set_fontsize](py_dpi_scale(plt, sp[:titlefontsize]))
|
||||
ax[func][:set_family](sp[:titlefontfamily])
|
||||
ax[func][:set_color](py_color(sp[:titlefontcolor]))
|
||||
# ax[:set_title](sp[:title], loc = loc)
|
||||
@@ -1003,9 +1036,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
fig = plt.o
|
||||
cbax = fig[:add_axes]([0.8,0.1,0.03,0.8], label = string(gensym()))
|
||||
cb = fig[:colorbar](handle; cax = cbax, kw...)
|
||||
cb[:set_label](sp[:colorbar_title],size=py_thickness_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor]))
|
||||
cb[:set_label](sp[:colorbar_title],size=py_dpi_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor]))
|
||||
for lab in cb[:ax][:yaxis][:get_ticklabels]()
|
||||
lab[:set_fontsize](py_thickness_scale(plt, sp[:yaxis][:tickfontsize]))
|
||||
lab[:set_fontsize](py_dpi_scale(plt, sp[:yaxis][:tickfontsize]))
|
||||
lab[:set_family](sp[:yaxis][:tickfontfamily])
|
||||
lab[:set_color](py_color(sp[:yaxis][:tickfontcolor]))
|
||||
end
|
||||
@@ -1015,14 +1048,12 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
|
||||
# framestyle
|
||||
if !ispolar(sp) && !is3d(sp)
|
||||
ax[:spines]["left"][:set_linewidth](py_thickness_scale(plt, 1))
|
||||
ax[:spines]["bottom"][:set_linewidth](py_thickness_scale(plt, 1))
|
||||
if sp[:framestyle] == :semi
|
||||
intensity = 0.5
|
||||
ax[:spines]["right"][:set_alpha](intensity)
|
||||
ax[:spines]["top"][:set_alpha](intensity)
|
||||
ax[:spines]["right"][:set_linewidth](py_thickness_scale(plt, intensity))
|
||||
ax[:spines]["top"][:set_linewidth](py_thickness_scale(plt, intensity))
|
||||
ax[:spines]["right"][:set_linewidth](intensity)
|
||||
ax[:spines]["top"][:set_linewidth](intensity)
|
||||
elseif sp[:framestyle] in (:axes, :origin)
|
||||
ax[:spines]["right"][:set_visible](false)
|
||||
ax[:spines]["top"][:set_visible](false)
|
||||
@@ -1035,8 +1066,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
spine[:set_visible](false)
|
||||
end
|
||||
if sp[:framestyle] == :zerolines
|
||||
ax[:axhline](y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
|
||||
ax[:axvline](x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
|
||||
ax[:axhline](y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = 0.75)
|
||||
ax[:axvline](x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = 0.75)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1066,13 +1097,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
|
||||
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
|
||||
ax[Symbol("set_", letter, "label")](axis[:guide])
|
||||
if get(axis.plotattributes, :flip, false)
|
||||
if get(axis.d, :flip, false)
|
||||
ax[Symbol("invert_", letter, "axis")]()
|
||||
end
|
||||
pyaxis[:label][:set_fontsize](py_thickness_scale(plt, axis[:guidefontsize]))
|
||||
pyaxis[:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefontsize]))
|
||||
pyaxis[:label][:set_family](axis[:guidefontfamily])
|
||||
for lab in ax[Symbol("get_", letter, "ticklabels")]()
|
||||
lab[:set_fontsize](py_thickness_scale(plt, axis[:tickfontsize]))
|
||||
lab[:set_fontsize](py_dpi_scale(plt, axis[:tickfontsize]))
|
||||
lab[:set_family](axis[:tickfontfamily])
|
||||
lab[:set_rotation](axis[:rotation])
|
||||
end
|
||||
@@ -1081,7 +1112,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
pyaxis[:grid](true,
|
||||
color = fgcolor,
|
||||
linestyle = py_linestyle(:line, axis[:gridstyle]),
|
||||
linewidth = py_thickness_scale(plt, axis[:gridlinewidth]),
|
||||
linewidth = axis[:gridlinewidth],
|
||||
alpha = axis[:gridalpha])
|
||||
ax[:set_axisbelow](true)
|
||||
else
|
||||
@@ -1178,7 +1209,7 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
|
||||
rightpad += sp[:right_margin]
|
||||
bottompad += sp[:bottom_margin]
|
||||
|
||||
dpi_factor = Plots.DPI / sp.plt[:dpi]
|
||||
dpi_factor = sp.plt[:thickness_scaling] * Plots.DPI / sp.plt[:dpi]
|
||||
|
||||
sp.minpad = Tuple(dpi_factor .* [leftpad, toppad, rightpad, bottompad])
|
||||
end
|
||||
@@ -1201,7 +1232,7 @@ function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText)
|
||||
horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign),
|
||||
verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign),
|
||||
rotation = val.font.rotation * 180 / π,
|
||||
size = py_thickness_scale(sp.plt, val.font.pointsize),
|
||||
size = py_dpi_scale(sp.plt, val.font.pointsize),
|
||||
zorder = 999
|
||||
)
|
||||
end
|
||||
@@ -1221,7 +1252,6 @@ const _pyplot_legend_pos = KW(
|
||||
|
||||
function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
leg = sp[:legend]
|
||||
clims = get_clims(sp)
|
||||
if leg != :none
|
||||
# gotta do this to ensure both axes are included
|
||||
labels = []
|
||||
@@ -1231,19 +1261,19 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
# add a line/marker and a label
|
||||
push!(handles, if series[:seriestype] == :shape || series[:fillrange] != nothing
|
||||
pypatches[:Patch](
|
||||
edgecolor = py_color(get_linecolor(series, clims), get_linealpha(series)),
|
||||
facecolor = py_color(get_fillcolor(series, clims), get_fillalpha(series)),
|
||||
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
edgecolor = py_color(get_linecolor(series), get_linealpha(series)),
|
||||
facecolor = py_color(get_fillcolor(series), get_fillalpha(series)),
|
||||
linewidth = py_dpi_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
linestyle = py_linestyle(series[:seriestype], get_linestyle(series))
|
||||
)
|
||||
elseif series[:seriestype] in (:path, :straightline)
|
||||
PyPlot.plt[:Line2D]((0,1),(0,0),
|
||||
color = py_color(get_linecolor(series, clims), get_linealpha(series)),
|
||||
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
color = py_color(get_linecolor(series), get_linealpha(series)),
|
||||
linewidth = py_dpi_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
linestyle = py_linestyle(:path, get_linestyle(series)),
|
||||
marker = py_marker(series[:markershape]),
|
||||
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
|
||||
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series, clims), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
|
||||
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
|
||||
)
|
||||
else
|
||||
series[:serieshandle][1]
|
||||
@@ -1258,13 +1288,11 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
labels,
|
||||
loc = get(_pyplot_legend_pos, leg, "best"),
|
||||
scatterpoints = 1,
|
||||
fontsize = py_thickness_scale(plt, sp[:legendfontsize]),
|
||||
fontsize = py_dpi_scale(plt, sp[:legendfontsize]),
|
||||
facecolor = py_color(sp[:background_color_legend]),
|
||||
edgecolor = py_color(sp[:foreground_color_legend]),
|
||||
framealpha = alpha(plot_color(sp[:background_color_legend])),
|
||||
)
|
||||
frame = leg[:get_frame]()
|
||||
frame[:set_linewidth](py_thickness_scale(plt, 1))
|
||||
leg[:set_zorder](1000)
|
||||
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
|
||||
|
||||
@@ -1332,7 +1360,7 @@ for (mime, fmt) in _pyplot_mimeformats
|
||||
# figsize = map(px2inch, plt[:size]),
|
||||
facecolor = fig[:get_facecolor](),
|
||||
edgecolor = "none",
|
||||
dpi = plt[:dpi]
|
||||
dpi = plt[:dpi] * plt[:thickness_scaling]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
# [ADD BACKEND WEBSITE]
|
||||
|
||||
import [PkgName]
|
||||
export [PkgName]
|
||||
push!(_initialized_backends, [pgkname]::Symbol)
|
||||
function _initialize_backend(::[PkgName]Backend; kw...)
|
||||
@eval begin
|
||||
import [PkgName]
|
||||
export [PkgName]
|
||||
# todo: other initialization that needs to be eval-ed
|
||||
end
|
||||
# todo: other initialization
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -49,7 +54,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
function _update_plot_object(plt::Plot{[PkgName]Backend})
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
|
||||
end
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
:label,
|
||||
:legend,
|
||||
@@ -25,10 +29,26 @@ const _unicodeplots_scale = [:identity]
|
||||
|
||||
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warnOnUnsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
|
||||
warnOnUnsupported_args(::UnicodePlotsBackend, d::KW) = nothing
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::UnicodePlotsBackend)
|
||||
"""
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.build("UnicodePlots")
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::UnicodePlotsBackend; kw...)
|
||||
@eval begin
|
||||
import UnicodePlots
|
||||
export UnicodePlots
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
const _canvas_type = Ref(:auto)
|
||||
|
||||
function _canvas_map()
|
||||
@@ -104,7 +124,7 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
for series in series_list(sp)
|
||||
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
|
||||
addUnicodeSeries!(o, series.d, sp[:legend] != :none, xlim, ylim)
|
||||
end
|
||||
|
||||
# save the object
|
||||
@@ -114,17 +134,17 @@ end
|
||||
|
||||
|
||||
# add a single series
|
||||
function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
|
||||
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
|
||||
# get the function, or special handling for step/bar/hist
|
||||
st = plotattributes[:seriestype]
|
||||
st = d[:seriestype]
|
||||
if st == :histogram2d
|
||||
UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
|
||||
UnicodePlots.densityplot!(o, d[:x], d[:y])
|
||||
return
|
||||
end
|
||||
|
||||
if st in (:path, :straightline)
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif st == :scatter || plotattributes[:markershape] != :none
|
||||
elseif st == :scatter || d[:markershape] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
# elseif st == :bar
|
||||
# func = UnicodePlots.barplot!
|
||||
@@ -136,16 +156,16 @@ function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
|
||||
|
||||
# get the series data and label
|
||||
x, y = if st == :straightline
|
||||
straightline_data(plotattributes)
|
||||
straightline_data(d)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
else
|
||||
[collect(float(plotattributes[s])) for s in (:x, :y)]
|
||||
[collect(float(d[s])) for s in (:x, :y)]
|
||||
end
|
||||
label = addlegend ? plotattributes[:label] : ""
|
||||
label = addlegend ? d[:label] : ""
|
||||
|
||||
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
|
||||
color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto
|
||||
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
|
||||
|
||||
# add the series
|
||||
x, y = Plots.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
# NOTE: backend should implement `html_body` and `html_head`
|
||||
|
||||
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
|
||||
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" begin
|
||||
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
|
||||
end
|
||||
|
||||
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
|
||||
"""
|
||||
|
||||
+9
-12
@@ -7,7 +7,7 @@ nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
|
||||
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
|
||||
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
|
||||
compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : angle)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
|
||||
@@ -297,7 +297,7 @@ function font(args...)
|
||||
elseif typeof(arg) <: Real
|
||||
rotation = convert(Float64, arg)
|
||||
else
|
||||
@warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -396,7 +396,7 @@ function stroke(args...; alpha = nothing)
|
||||
elseif allReals(arg)
|
||||
width = arg
|
||||
else
|
||||
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
|
||||
warn("Unused stroke arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -429,7 +429,7 @@ function brush(args...; alpha = nothing)
|
||||
elseif allReals(arg)
|
||||
size = arg
|
||||
else
|
||||
@warn("Unused brush arg: $arg ($(typeof(arg)))")
|
||||
warn("Unused brush arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -460,7 +460,7 @@ function series_annotations(strs::AbstractVector, args...)
|
||||
elseif is_2tuple(arg)
|
||||
scalefactor = arg
|
||||
else
|
||||
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
# if scalefactor != 1
|
||||
@@ -523,12 +523,9 @@ mutable struct EachAnn
|
||||
x
|
||||
y
|
||||
end
|
||||
|
||||
function Base.iterate(ea::EachAnn, i = 1)
|
||||
if ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
|
||||
return nothing
|
||||
end
|
||||
|
||||
Base.start(ea::EachAnn) = 1
|
||||
Base.done(ea::EachAnn, i) = ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
|
||||
function Base.next(ea::EachAnn, i)
|
||||
tmp = _cycle(ea.anns.strs,i)
|
||||
str,fnt = if isa(tmp, PlotText)
|
||||
tmp.str, tmp.font
|
||||
@@ -704,7 +701,7 @@ function arrow(args...)
|
||||
elseif T <: Tuple && length(arg) == 2
|
||||
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
|
||||
else
|
||||
@warn("Skipped arrow arg $arg")
|
||||
warn("Skipped arrow arg $arg")
|
||||
end
|
||||
end
|
||||
Arrow(style, side, headlength, headwidth)
|
||||
|
||||
@@ -95,9 +95,9 @@ const _glyphtypes = KW(
|
||||
)
|
||||
|
||||
|
||||
function bokeh_glyph_type(plotattributes::KW)
|
||||
st = plotattributes[:seriestype]
|
||||
mt = plotattributes[:markershape]
|
||||
function bokeh_glyph_type(d::KW)
|
||||
st = d[:seriestype]
|
||||
mt = d[:markershape]
|
||||
if st == :scatter && mt == :none
|
||||
mt = :circle
|
||||
end
|
||||
@@ -125,7 +125,7 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# function _create_plot(pkg::BokehBackend, plotattributes::KW)
|
||||
# function _create_plot(pkg::BokehBackend, d::KW)
|
||||
function _create_backend_figure(plt::Plot{BokehBackend})
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
@@ -142,34 +142,34 @@ function _create_backend_figure(plt::Plot{BokehBackend})
|
||||
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
|
||||
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
|
||||
|
||||
# Plot(bplt, pkg, 0, plotattributes, KW[])
|
||||
# Plot(bplt, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
# function _series_added(::BokehBackend, plt::Plot, plotattributes::KW)
|
||||
# function _series_added(::BokehBackend, plt::Plot, d::KW)
|
||||
function _series_added(plt::Plot{BokehBackend}, series::Series)
|
||||
bdata = Dict{Symbol, Vector}(:x => collect(series.plotattributes[:x]), :y => collect(series.plotattributes[:y]))
|
||||
bdata = Dict{Symbol, Vector}(:x => collect(series.d[:x]), :y => collect(series.d[:y]))
|
||||
|
||||
glyph = Bokeh.Bokehjs.Glyph(
|
||||
glyphtype = bokeh_glyph_type(plotattributes),
|
||||
linecolor = webcolor(plotattributes[:linecolor]), # shape's stroke or line color
|
||||
linewidth = plotattributes[:linewidth], # shape's stroke width or line width
|
||||
fillcolor = webcolor(plotattributes[:markercolor]),
|
||||
size = ceil(Int, plotattributes[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
|
||||
dash = get_stroke_vector(plotattributes[:linestyle])
|
||||
glyphtype = bokeh_glyph_type(d),
|
||||
linecolor = webcolor(d[:linecolor]), # shape's stroke or line color
|
||||
linewidth = d[:linewidth], # shape's stroke width or line width
|
||||
fillcolor = webcolor(d[:markercolor]),
|
||||
size = ceil(Int, d[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
|
||||
dash = get_stroke_vector(d[:linestyle])
|
||||
)
|
||||
|
||||
legend = nothing # TODO
|
||||
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
|
||||
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot_object(plt::Plot{BokehBackend}, plotattributes::KW)
|
||||
function _update_plot_object(plt::Plot{BokehBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
+108
-108
@@ -51,32 +51,32 @@ end
|
||||
# Base.size(v::MissingVec) = (1,)
|
||||
# Base.getindex(v::MissingVec, i::Integer) = 0.0
|
||||
|
||||
function createGadflyPlotObject(plotattributes::KW)
|
||||
function createGadflyPlotObject(d::KW)
|
||||
gplt = Gadfly.Plot()
|
||||
gplt.mapping = Dict()
|
||||
gplt.data_source = Gadfly.DataFrames.DataFrame()
|
||||
# gplt.layers = gplt.layers[1:0]
|
||||
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
|
||||
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(plotattributes[:xguide]),
|
||||
Gadfly.Guide.ylabel(plotattributes[:yguide]),
|
||||
Gadfly.Guide.title(plotattributes[:title])]
|
||||
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xguide]),
|
||||
Gadfly.Guide.ylabel(d[:yguide]),
|
||||
Gadfly.Guide.title(d[:title])]
|
||||
gplt
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function getLineGeom(plotattributes::KW)
|
||||
st = plotattributes[:seriestype]
|
||||
xbins, ybins = maketuple(plotattributes[:bins])
|
||||
function getLineGeom(d::KW)
|
||||
st = d[:seriestype]
|
||||
xbins, ybins = maketuple(d[:bins])
|
||||
if st == :hexb
|
||||
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
|
||||
elseif st == :histogram2d
|
||||
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
|
||||
elseif st == :histogram
|
||||
Gadfly.Geom.histogram(bincount = xbins,
|
||||
orientation = isvertical(plotattributes) ? :vertical : :horizontal,
|
||||
position = plotattributes[:bar_position] == :stack ? :stack : :dodge)
|
||||
orientation = isvertical(d) ? :vertical : :horizontal,
|
||||
position = d[:bar_position] == :stack ? :stack : :dodge)
|
||||
elseif st == :path
|
||||
Gadfly.Geom.path
|
||||
elseif st in (:bar, :sticks)
|
||||
@@ -90,7 +90,7 @@ function getLineGeom(plotattributes::KW)
|
||||
elseif st == :vline
|
||||
Gadfly.Geom.vline
|
||||
elseif st == :contour
|
||||
Gadfly.Geom.contour(levels = plotattributes[:levels])
|
||||
Gadfly.Geom.contour(levels = d[:levels])
|
||||
# elseif st == :shape
|
||||
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
||||
else
|
||||
@@ -98,11 +98,11 @@ function getLineGeom(plotattributes::KW)
|
||||
end
|
||||
end
|
||||
|
||||
function get_extra_theme_args(plotattributes::KW, k::Symbol)
|
||||
function get_extra_theme_args(d::KW, k::Symbol)
|
||||
# gracefully handles old Gadfly versions
|
||||
extra_theme_args = KW()
|
||||
try
|
||||
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(plotattributes[k])
|
||||
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k])
|
||||
catch err
|
||||
if string(err) == "UndefVarError(:get_stroke_vector)"
|
||||
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
|
||||
@@ -113,53 +113,53 @@ function get_extra_theme_args(plotattributes::KW, k::Symbol)
|
||||
extra_theme_args
|
||||
end
|
||||
|
||||
function getGadflyLineTheme(plotattributes::KW)
|
||||
st = plotattributes[:seriestype]
|
||||
lc = convertColor(getColor(plotattributes[:linecolor]), plotattributes[:linealpha])
|
||||
fc = convertColor(getColor(plotattributes[:fillcolor]), plotattributes[:fillalpha])
|
||||
function getGadflyLineTheme(d::KW)
|
||||
st = d[:seriestype]
|
||||
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
|
||||
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
|
||||
|
||||
Gadfly.Theme(;
|
||||
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
|
||||
line_width = (st == :sticks ? 1 : plotattributes[:linewidth]) * Gadfly.px,
|
||||
# line_style = Gadfly.get_stroke_vector(plotattributes[:linestyle]),
|
||||
line_width = (st == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
|
||||
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
|
||||
lowlight_color = x->RGB(fc), # fill/ribbon
|
||||
lowlight_opacity = alpha(fc), # fill/ribbon
|
||||
bar_highlight = RGB(lc), # bars
|
||||
get_extra_theme_args(plotattributes, :linestyle)...
|
||||
get_extra_theme_args(d, :linestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
# add a line as a new layer
|
||||
function addGadflyLine!(plt::Plot, numlayers::Int, plotattributes::KW, geoms...)
|
||||
function addGadflyLine!(plt::Plot, numlayers::Int, d::KW, geoms...)
|
||||
gplt = getGadflyContext(plt)
|
||||
gfargs = vcat(geoms..., getGadflyLineTheme(plotattributes))
|
||||
gfargs = vcat(geoms..., getGadflyLineTheme(d))
|
||||
kwargs = KW()
|
||||
st = plotattributes[:seriestype]
|
||||
st = d[:seriestype]
|
||||
|
||||
# add a fill?
|
||||
if plotattributes[:fillrange] != nothing && st != :contour
|
||||
fillmin, fillmax = map(makevec, maketuple(plotattributes[:fillrange]))
|
||||
if d[:fillrange] != nothing && st != :contour
|
||||
fillmin, fillmax = map(makevec, maketuple(d[:fillrange]))
|
||||
nmin, nmax = length(fillmin), length(fillmax)
|
||||
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
|
||||
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
|
||||
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
|
||||
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
|
||||
push!(gfargs, Gadfly.Geom.ribbon)
|
||||
end
|
||||
|
||||
if st in (:hline, :vline)
|
||||
kwargs[st == :hline ? :yintercept : :xintercept] = plotattributes[:y]
|
||||
kwargs[st == :hline ? :yintercept : :xintercept] = d[:y]
|
||||
|
||||
else
|
||||
if st == :sticks
|
||||
w = 0.01 * mean(diff(plotattributes[:x]))
|
||||
kwargs[:xmin] = plotattributes[:x] - w
|
||||
kwargs[:xmax] = plotattributes[:x] + w
|
||||
w = 0.01 * mean(diff(d[:x]))
|
||||
kwargs[:xmin] = d[:x] - w
|
||||
kwargs[:xmax] = d[:x] + w
|
||||
elseif st == :contour
|
||||
kwargs[:z] = plotattributes[:z].surf
|
||||
addGadflyContColorScale(plt, plotattributes[:linecolor])
|
||||
kwargs[:z] = d[:z].surf
|
||||
addGadflyContColorScale(plt, d[:linecolor])
|
||||
end
|
||||
|
||||
kwargs[:x] = plotattributes[st == :histogram ? :y : :x]
|
||||
kwargs[:y] = plotattributes[:y]
|
||||
kwargs[:x] = d[st == :histogram ? :y : :x]
|
||||
kwargs[:y] = d[:y]
|
||||
|
||||
end
|
||||
|
||||
@@ -180,24 +180,24 @@ getMarkerGeom(other) = gadflyshape(get_shape(other))
|
||||
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
|
||||
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
|
||||
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
|
||||
function getMarkerGeom(plotattributes::KW)
|
||||
if plotattributes[:seriestype] == :shape
|
||||
function getMarkerGeom(d::KW)
|
||||
if d[:seriestype] == :shape
|
||||
Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
||||
else
|
||||
getMarkerGeom(plotattributes[:markershape])
|
||||
getMarkerGeom(d[:markershape])
|
||||
end
|
||||
end
|
||||
|
||||
function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
|
||||
c = getColor(plotattributes[:markercolor])
|
||||
α = plotattributes[:markeralpha]
|
||||
function getGadflyMarkerTheme(d::KW, attr::KW)
|
||||
c = getColor(d[:markercolor])
|
||||
α = d[:markeralpha]
|
||||
if α != nothing
|
||||
c = RGBA(RGB(c), α)
|
||||
end
|
||||
|
||||
ms = plotattributes[:markersize]
|
||||
ms = d[:markersize]
|
||||
ms = if typeof(ms) <: AVec
|
||||
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
|
||||
warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
|
||||
mean(ms) * Gadfly.px
|
||||
else
|
||||
ms * Gadfly.px
|
||||
@@ -206,10 +206,10 @@ function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
|
||||
Gadfly.Theme(;
|
||||
default_color = c,
|
||||
default_point_size = ms,
|
||||
discrete_highlight_color = c -> RGB(getColor(plotattributes[:markerstrokecolor])),
|
||||
highlight_width = plotattributes[:markerstrokewidth] * Gadfly.px,
|
||||
line_width = plotattributes[:markerstrokewidth] * Gadfly.px,
|
||||
# get_extra_theme_args(plotattributes, :markerstrokestyle)...
|
||||
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
|
||||
highlight_width = d[:markerstrokewidth] * Gadfly.px,
|
||||
line_width = d[:markerstrokewidth] * Gadfly.px,
|
||||
# get_extra_theme_args(d, :markerstrokestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
@@ -221,25 +221,25 @@ function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
|
||||
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
|
||||
end
|
||||
|
||||
function addGadflyMarker!(plt::Plot, numlayers::Int, plotattributes::KW, attr::KW, geoms...)
|
||||
gfargs = vcat(geoms..., getGadflyMarkerTheme(plotattributes, attr), getMarkerGeom(plotattributes))
|
||||
function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, attr::KW, geoms...)
|
||||
gfargs = vcat(geoms..., getGadflyMarkerTheme(d, attr), getMarkerGeom(d))
|
||||
kwargs = KW()
|
||||
|
||||
# handle continuous color scales for the markers
|
||||
zcolor = plotattributes[:marker_z]
|
||||
zcolor = d[:marker_z]
|
||||
if zcolor != nothing && typeof(zcolor) <: AVec
|
||||
kwargs[:color] = zcolor
|
||||
addGadflyContColorScale(plt, plotattributes[:markercolor])
|
||||
addGadflyContColorScale(plt, d[:markercolor])
|
||||
end
|
||||
|
||||
Gadfly.layer(gfargs...; x = plotattributes[:x], y = plotattributes[:y], order=numlayers, kwargs...)
|
||||
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function addToGadflyLegend(plt::Plot, plotattributes::KW)
|
||||
if plt.attr[:legend] != :none && plotattributes[:label] != ""
|
||||
function addToGadflyLegend(plt::Plot, d::KW)
|
||||
if plt.attr[:legend] != :none && d[:label] != ""
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add the legend if needed
|
||||
@@ -254,20 +254,20 @@ function addToGadflyLegend(plt::Plot, plotattributes::KW)
|
||||
# since gadfly will call unique(colors), but doesn't also merge the rows that match
|
||||
# Should ensure from this side that colors which are the same are merged together
|
||||
|
||||
c = getColor(plotattributes[plotattributes[:markershape] == :none ? :linecolor : :markercolor])
|
||||
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
|
||||
foundit = false
|
||||
|
||||
# extend the label if we found this color
|
||||
for i in 1:length(guide.colors)
|
||||
if RGB(c) == guide.colors[i]
|
||||
guide.labels[i] *= ", " * plotattributes[:label]
|
||||
guide.labels[i] *= ", " * d[:label]
|
||||
foundit = true
|
||||
end
|
||||
end
|
||||
|
||||
# didn't find the color, so add a new entry into the legend
|
||||
if !foundit
|
||||
push!(guide.labels, plotattributes[:label])
|
||||
push!(guide.labels, d[:label])
|
||||
push!(guide.colors, c)
|
||||
end
|
||||
end
|
||||
@@ -279,40 +279,40 @@ getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : A
|
||||
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
|
||||
|
||||
|
||||
function addGadflySeries!(plt::Plot, plotattributes::KW)
|
||||
function addGadflySeries!(plt::Plot, d::KW)
|
||||
layers = Gadfly.Layer[]
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add a regression line?
|
||||
# TODO: make more flexible
|
||||
smooth = getGadflySmoothing(plotattributes[:smooth])
|
||||
smooth = getGadflySmoothing(d[:smooth])
|
||||
|
||||
# lines
|
||||
geom = getLineGeom(plotattributes)
|
||||
geom = getLineGeom(d)
|
||||
if geom != nothing
|
||||
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), plotattributes, geom, smooth...))
|
||||
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
|
||||
smooth = Any[] # don't add a regression for markers too
|
||||
end
|
||||
|
||||
# special handling for ohlc and scatter
|
||||
st = plotattributes[:seriestype]
|
||||
st = d[:seriestype]
|
||||
# if st == :ohlc
|
||||
# error("Haven't re-implemented after refactoring")
|
||||
if st in (:histogram2d, :hexbin) && (isa(plotattributes[:fillcolor], ColorGradient) || isa(plotattributes[:fillcolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(plotattributes[:fillcolor], p))))
|
||||
elseif st == :scatter && plotattributes[:markershape] == :none
|
||||
plotattributes[:markershape] = :circle
|
||||
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
|
||||
elseif st == :scatter && d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# markers
|
||||
if plotattributes[:markershape] != :none || st == :shape
|
||||
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), plotattributes, plt.attr, smooth...))
|
||||
if d[:markershape] != :none || st == :shape
|
||||
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.attr, smooth...))
|
||||
end
|
||||
|
||||
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, plotattributes)
|
||||
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, d)
|
||||
|
||||
# now save the layers that apply to this series
|
||||
plotattributes[:gadflylayers] = layers
|
||||
d[:gadflylayers] = layers
|
||||
prepend!(gplt.layers, layers)
|
||||
end
|
||||
|
||||
@@ -322,10 +322,10 @@ end
|
||||
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
|
||||
|
||||
# # colorgroup
|
||||
# z = plotattributes[:z]
|
||||
# z = d[:z]
|
||||
|
||||
# # handle line segments of different colors
|
||||
# cscheme = plotattributes[:linecolor]
|
||||
# cscheme = d[:linecolor]
|
||||
# if isa(cscheme, ColorVector)
|
||||
# # create a color scale, and set the color group to the index of the color
|
||||
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
|
||||
@@ -333,10 +333,10 @@ end
|
||||
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
|
||||
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
|
||||
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
|
||||
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(plotattributes[:y])]
|
||||
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(d[:y])]
|
||||
# cs = collect(repeat(csindices', 2, 1))[1:end-1]
|
||||
# grp = collect(repeat((1:length(plotattributes[:y]))', 2, 1))[1:end-1]
|
||||
# plotattributes[:x], plotattributes[:y] = map(createSegments, (plotattributes[:x], plotattributes[:y]))
|
||||
# grp = collect(repeat((1:length(d[:y]))', 2, 1))[1:end-1]
|
||||
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
|
||||
# colorgroup = [(:linecolor, cs), (:group, grp)]
|
||||
|
||||
|
||||
@@ -388,11 +388,11 @@ continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScal
|
||||
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
|
||||
|
||||
|
||||
function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
|
||||
function getGadflyScaleFunction(d::KW, isx::Bool)
|
||||
scalekey = isx ? :xscale : :yscale
|
||||
hasScaleKey = haskey(plotattributes, scalekey)
|
||||
hasScaleKey = haskey(d, scalekey)
|
||||
if hasScaleKey
|
||||
scale = plotattributes[scalekey]
|
||||
scale = d[scalekey]
|
||||
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
|
||||
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
|
||||
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
|
||||
@@ -403,15 +403,15 @@ function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
function addGadflyLimitsScale(gplt, plotattributes::KW, isx::Bool)
|
||||
gfunc, hasScaleKey, func = getGadflyScaleFunction(plotattributes, isx)
|
||||
function addGadflyLimitsScale(gplt, d::KW, isx::Bool)
|
||||
gfunc, hasScaleKey, func = getGadflyScaleFunction(d, isx)
|
||||
|
||||
# do we want to add min/max limits for the axis?
|
||||
limsym = isx ? :xlims : :ylims
|
||||
limargs = Any[]
|
||||
|
||||
# map :auto to nothing, otherwise add to limargs
|
||||
lims = get(plotattributes, limsym, :auto)
|
||||
lims = get(d, limsym, :auto)
|
||||
if lims == :auto
|
||||
lims = nothing
|
||||
else
|
||||
@@ -432,7 +432,7 @@ function addGadflyLimitsScale(gplt, plotattributes::KW, isx::Bool)
|
||||
lims, func
|
||||
end
|
||||
|
||||
function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yfunc)
|
||||
function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
|
||||
if isa(gplt.coord, Gadfly.Coord.Cartesian)
|
||||
gplt.coord = Gadfly.Coord.cartesian(
|
||||
gplt.coord.xvars,
|
||||
@@ -441,16 +441,16 @@ function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yf
|
||||
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
|
||||
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
|
||||
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
|
||||
xflip = get(plotattributes, :xflip, gplt.coord.xflip),
|
||||
yflip = get(plotattributes, :yflip, gplt.coord.yflip),
|
||||
xflip = get(d, :xflip, gplt.coord.xflip),
|
||||
yflip = get(d, :yflip, gplt.coord.yflip),
|
||||
fixed = gplt.coord.fixed,
|
||||
aspect_ratio = gplt.coord.aspect_ratio,
|
||||
raster = gplt.coord.raster
|
||||
)
|
||||
else
|
||||
gplt.coord = Gadfly.Coord.Cartesian(
|
||||
xflip = get(plotattributes, :xflip, false),
|
||||
yflip = get(plotattributes, :yflip, false)
|
||||
xflip = get(d, :xflip, false),
|
||||
yflip = get(d, :yflip, false)
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -464,37 +464,37 @@ function findGuideAndSet(gplt, t::DataType, args...; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
function updateGadflyGuides(plt::Plot, plotattributes::KW)
|
||||
function updateGadflyGuides(plt::Plot, d::KW)
|
||||
gplt = getGadflyContext(plt)
|
||||
haskey(plotattributes, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(plotattributes[:title]))
|
||||
haskey(plotattributes, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(plotattributes[:xguide]))
|
||||
haskey(plotattributes, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(plotattributes[:yguide]))
|
||||
haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title]))
|
||||
haskey(d, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xguide]))
|
||||
haskey(d, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:yguide]))
|
||||
|
||||
xlims, xfunc = addGadflyLimitsScale(gplt, plotattributes, true)
|
||||
ylims, yfunc = addGadflyLimitsScale(gplt, plotattributes, false)
|
||||
xlims, xfunc = addGadflyLimitsScale(gplt, d, true)
|
||||
ylims, yfunc = addGadflyLimitsScale(gplt, d, false)
|
||||
|
||||
ticks = get(plotattributes, :xticks, :auto)
|
||||
ticks = get(d, :xticks, :auto)
|
||||
if ticks == :none
|
||||
_remove_axis(plt, true)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, true)
|
||||
end
|
||||
ticks = get(plotattributes, :yticks, :auto)
|
||||
ticks = get(d, :yticks, :auto)
|
||||
if ticks == :none
|
||||
_remove_axis(plt, false)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, false)
|
||||
end
|
||||
|
||||
updateGadflyAxisFlips(gplt, plotattributes, xlims, ylims, xfunc, yfunc)
|
||||
updateGadflyAxisFlips(gplt, d, xlims, ylims, xfunc, yfunc)
|
||||
end
|
||||
|
||||
function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
|
||||
function updateGadflyPlotTheme(plt::Plot, d::KW)
|
||||
kwargs = KW()
|
||||
|
||||
# colors
|
||||
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
|
||||
map(s -> getColor(plotattributes[s]), (
|
||||
map(s -> getColor(d[s]), (
|
||||
:background_color_inside,
|
||||
:foreground_color_grid,
|
||||
:foreground_color_text,
|
||||
@@ -503,17 +503,17 @@ function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
|
||||
))
|
||||
|
||||
# # hide the legend?
|
||||
leg = plotattributes[plotattributes[:legend] == :none ? :colorbar : :legend]
|
||||
leg = d[d[:legend] == :none ? :colorbar : :legend]
|
||||
if leg != :best
|
||||
kwargs[:key_position] = leg == :inside ? :right : leg
|
||||
end
|
||||
|
||||
if !get(plotattributes, :grid, true)
|
||||
if !get(d, :grid, true)
|
||||
kwargs[:grid_color] = gridcolor
|
||||
end
|
||||
|
||||
# fonts
|
||||
tfont, gfont, lfont = plotattributes[:tickfont], plotattributes[:guidefont], plotattributes[:legendfont]
|
||||
tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont]
|
||||
|
||||
getGadflyContext(plt).theme = Gadfly.Theme(;
|
||||
background_color = insidecolor,
|
||||
@@ -568,9 +568,9 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
# function _create_plot(pkg::GadflyBackend, plotattributes::KW)
|
||||
# gplt = createGadflyPlotObject(plotattributes)
|
||||
# Plot(gplt, pkg, 0, plotattributes, KW[])
|
||||
# function _create_plot(pkg::GadflyBackend, d::KW)
|
||||
# gplt = createGadflyPlotObject(d)
|
||||
# Plot(gplt, pkg, 0, d, KW[])
|
||||
# end
|
||||
function _create_backend_figure(plt::Plot{GadflyBackend})
|
||||
createGadflyPlotObject(plt.attr)
|
||||
@@ -578,7 +578,7 @@ end
|
||||
|
||||
|
||||
# plot one data series
|
||||
# function _series_added(::GadflyBackend, plt::Plot, plotattributes::KW)
|
||||
# function _series_added(::GadflyBackend, plt::Plot, d::KW)
|
||||
function _series_added(plt::Plot{GadflyBackend}, series::Series)
|
||||
# first clear out the temporary layer
|
||||
gplt = getGadflyContext(plt)
|
||||
@@ -586,16 +586,16 @@ function _series_added(plt::Plot{GadflyBackend}, series::Series)
|
||||
gplt.layers = gplt.layers[2:end]
|
||||
end
|
||||
|
||||
addGadflySeries!(plt, series.plotattributes)
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
addGadflySeries!(plt, series.d)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{GadflyBackend}, plotattributes::KW)
|
||||
updateGadflyGuides(plt, plotattributes)
|
||||
updateGadflyPlotTheme(plt, plotattributes)
|
||||
function _update_plot_object(plt::Plot{GadflyBackend}, d::KW)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ function _initialize_backend(::ImmerseBackend; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
function createImmerseFigure(plotattributes::KW)
|
||||
w,h = plotattributes[:size]
|
||||
figidx = Immerse.figure(; name = plotattributes[:window_title], width = w, height = h)
|
||||
function createImmerseFigure(d::KW)
|
||||
w,h = d[:size]
|
||||
figidx = Immerse.figure(; name = d[:window_title], width = w, height = h)
|
||||
Immerse.Figure(figidx)
|
||||
end
|
||||
|
||||
@@ -28,12 +28,12 @@ end
|
||||
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
# function _create_plot(pkg::ImmerseBackend, plotattributes::KW)
|
||||
# function _create_plot(pkg::ImmerseBackend, d::KW)
|
||||
# # create the underlying Gadfly.Plot object
|
||||
# gplt = createGadflyPlotObject(plotattributes)
|
||||
# gplt = createGadflyPlotObject(d)
|
||||
#
|
||||
# # save both the Immerse.Figure and the Gadfly.Plot
|
||||
# Plot((nothing,gplt), pkg, 0, plotattributes, KW[])
|
||||
# Plot((nothing,gplt), pkg, 0, d, KW[])
|
||||
# end
|
||||
function _create_backend_figure(plt::Plot{ImmerseBackend})
|
||||
(nothing, createGadflyPlotObject(plt.attr))
|
||||
@@ -41,20 +41,20 @@ end
|
||||
|
||||
|
||||
# # plot one data series
|
||||
# function _series_added(::ImmerseBackend, plt::Plot, plotattributes::KW)
|
||||
# addGadflySeries!(plt, plotattributes)
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# function _series_added(::ImmerseBackend, plt::Plot, d::KW)
|
||||
# addGadflySeries!(plt, d)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
# end
|
||||
|
||||
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
|
||||
addGadflySeries!(plt, series.plotattributes)
|
||||
addGadflySeries!(plt, series.d)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{ImmerseBackend}, plotattributes::KW)
|
||||
updateGadflyGuides(plt, plotattributes)
|
||||
updateGadflyPlotTheme(plt, plotattributes)
|
||||
function _update_plot_object(plt::Plot{ImmerseBackend}, d::KW)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
|
||||
|
||||
@@ -94,10 +94,10 @@ end
|
||||
#
|
||||
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
|
||||
# # create the Gtk window with vertical box vsep
|
||||
# plotattributes = getattr(subplt,1)
|
||||
# w,h = plotattributes[:size]
|
||||
# d = getattr(subplt,1)
|
||||
# w,h = d[:size]
|
||||
# vsep = Gtk.GtkBoxLeaf(:v)
|
||||
# win = Gtk.GtkWindowLeaf(vsep, plotattributes[:window_title], w, h)
|
||||
# win = Gtk.GtkWindowLeaf(vsep, d[:window_title], w, h)
|
||||
#
|
||||
# figindices = []
|
||||
# row = Gtk.GtkBoxLeaf(:h)
|
||||
|
||||
@@ -52,84 +52,84 @@ const _qwtAliases = KW(
|
||||
:star8 => :star2,
|
||||
)
|
||||
|
||||
function fixcolors(plotattributes::KW)
|
||||
for (k,v) in plotattributes
|
||||
function fixcolors(d::KW)
|
||||
for (k,v) in d
|
||||
if typeof(v) <: ColorScheme
|
||||
plotattributes[k] = getColor(v)
|
||||
d[k] = getColor(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function replaceQwtAliases(plotattributes, s)
|
||||
if haskey(_qwtAliases, plotattributes[s])
|
||||
plotattributes[s] = _qwtAliases[plotattributes[s]]
|
||||
function replaceQwtAliases(d, s)
|
||||
if haskey(_qwtAliases, d[s])
|
||||
d[s] = _qwtAliases[d[s]]
|
||||
end
|
||||
end
|
||||
|
||||
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
||||
plotattributes = KW(kw)
|
||||
st = plotattributes[:seriestype]
|
||||
d = KW(kw)
|
||||
st = d[:seriestype]
|
||||
if st == :scatter
|
||||
plotattributes[:seriestype] = :none
|
||||
if plotattributes[:markershape] == :none
|
||||
plotattributes[:markershape] = :circle
|
||||
d[:seriestype] = :none
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
elseif st in (:hline, :vline)
|
||||
addLineMarker(plt, plotattributes)
|
||||
plotattributes[:seriestype] = :none
|
||||
plotattributes[:markershape] = :circle
|
||||
plotattributes[:markersize] = 1
|
||||
addLineMarker(plt, d)
|
||||
d[:seriestype] = :none
|
||||
d[:markershape] = :circle
|
||||
d[:markersize] = 1
|
||||
if st == :vline
|
||||
plotattributes[:x], plotattributes[:y] = plotattributes[:y], plotattributes[:x]
|
||||
d[:x], d[:y] = d[:y], d[:x]
|
||||
end
|
||||
|
||||
elseif !iscreating && st == :bar
|
||||
plotattributes = barHack(; kw...)
|
||||
d = barHack(; kw...)
|
||||
elseif !iscreating && st == :histogram
|
||||
plotattributes = barHack(; histogramHack(; kw...)...)
|
||||
d = barHack(; histogramHack(; kw...)...)
|
||||
end
|
||||
|
||||
replaceQwtAliases(plotattributes, :seriestype)
|
||||
replaceQwtAliases(plotattributes, :markershape)
|
||||
replaceQwtAliases(d, :seriestype)
|
||||
replaceQwtAliases(d, :markershape)
|
||||
|
||||
for k in keys(plotattributes)
|
||||
for k in keys(d)
|
||||
if haskey(_qwtAliases, k)
|
||||
plotattributes[_qwtAliases[k]] = plotattributes[k]
|
||||
d[_qwtAliases[k]] = d[k]
|
||||
end
|
||||
end
|
||||
|
||||
plotattributes[:x] = collect(plotattributes[:x])
|
||||
plotattributes[:y] = collect(plotattributes[:y])
|
||||
d[:x] = collect(d[:x])
|
||||
d[:y] = collect(d[:y])
|
||||
|
||||
plotattributes
|
||||
d
|
||||
end
|
||||
|
||||
# function _create_plot(pkg::QwtBackend, plotattributes::KW)
|
||||
# function _create_plot(pkg::QwtBackend, d::KW)
|
||||
function _create_backend_figure(plt::Plot{QwtBackend})
|
||||
fixcolors(plt.attr)
|
||||
dumpdict(plt.attr,"\n\n!!! plot")
|
||||
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
|
||||
# plt = Plot(o, pkg, 0, plotattributes, KW[])
|
||||
# plt = Plot(o, pkg, 0, d, KW[])
|
||||
# plt
|
||||
end
|
||||
|
||||
# function _series_added(::QwtBackend, plt::Plot, plotattributes::KW)
|
||||
# function _series_added(::QwtBackend, plt::Plot, d::KW)
|
||||
function _series_added(plt::Plot{QwtBackend}, series::Series)
|
||||
plotattributes = adjustQwtKeywords(plt, false; series.plotattributes...)
|
||||
fixcolors(plotattributes)
|
||||
dumpdict(plotattributes,"\n\n!!! plot!")
|
||||
Qwt.oplot(plt.o; plotattributes...)
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
d = adjustQwtKeywords(plt, false; series.d...)
|
||||
fixcolors(d)
|
||||
dumpdict(d,"\n\n!!! plot!")
|
||||
Qwt.oplot(plt.o; d...)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function updateLimsAndTicks(plt::Plot{QwtBackend}, plotattributes::KW, isx::Bool)
|
||||
lims = get(plotattributes, isx ? :xlims : :ylims, nothing)
|
||||
ticks = get(plotattributes, isx ? :xticks : :yticks, nothing)
|
||||
function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
|
||||
lims = get(d, isx ? :xlims : :ylims, nothing)
|
||||
ticks = get(d, isx ? :xticks : :yticks, nothing)
|
||||
w = plt.o.widget
|
||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
||||
|
||||
@@ -150,49 +150,49 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, plotattributes::KW, isx::Bool
|
||||
end
|
||||
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
|
||||
elseif !(ticks in (nothing, :none, :auto))
|
||||
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
|
||||
warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
|
||||
end
|
||||
|
||||
# change the scale
|
||||
scalesym = isx ? :xscale : :yscale
|
||||
if haskey(plotattributes, scalesym)
|
||||
scaletype = plotattributes[scalesym]
|
||||
if haskey(d, scalesym)
|
||||
scaletype = d[scalesym]
|
||||
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
|
||||
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
|
||||
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
|
||||
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
|
||||
scaletype in supported_scales() || @warn("Unsupported scale type: ", scaletype)
|
||||
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{QwtBackend}, plotattributes::KW)
|
||||
haskey(plotattributes, :title) && Qwt.title(plt.o, plotattributes[:title])
|
||||
haskey(plotattributes, :xguide) && Qwt.xlabel(plt.o, plotattributes[:xguide])
|
||||
haskey(plotattributes, :yguide) && Qwt.ylabel(plt.o, plotattributes[:yguide])
|
||||
updateLimsAndTicks(plt, plotattributes, true)
|
||||
updateLimsAndTicks(plt, plotattributes, false)
|
||||
function _update_plot_object(plt::Plot{QwtBackend}, d::KW)
|
||||
haskey(d, :title) && Qwt.title(plt.o, d[:title])
|
||||
haskey(d, :xguide) && Qwt.xlabel(plt.o, d[:xguide])
|
||||
haskey(d, :yguide) && Qwt.ylabel(plt.o, d[:yguide])
|
||||
updateLimsAndTicks(plt, d, true)
|
||||
updateLimsAndTicks(plt, d, false)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, plotattributes::KW)
|
||||
haskey(plotattributes, :size) && Qwt.resizewidget(plt.o, plotattributes[:size]...)
|
||||
haskey(plotattributes, :pos) && Qwt.movewidget(plt.o, plotattributes[:pos]...)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, d::KW)
|
||||
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
|
||||
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
|
||||
function addLineMarker(plt::Plot{QwtBackend}, plotattributes::KW)
|
||||
for yi in plotattributes[:y]
|
||||
function addLineMarker(plt::Plot{QwtBackend}, d::KW)
|
||||
for yi in d[:y]
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
ishorizontal = (plotattributes[:seriestype] == :hline)
|
||||
ishorizontal = (d[:seriestype] == :hline)
|
||||
marker[:setLineStyle](ishorizontal ? 1 : 2)
|
||||
marker[ishorizontal ? :setYValue : :setXValue](yi)
|
||||
qcolor = Qwt.convertRGBToQColor(getColor(plotattributes[:linecolor]))
|
||||
linestyle = plt.o.widget[:getLineStyle](string(plotattributes[:linestyle]))
|
||||
marker[:setLinePen](Qwt.QT.QPen(qcolor, plotattributes[:linewidth], linestyle))
|
||||
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
|
||||
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
|
||||
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
|
||||
@@ -75,10 +75,10 @@ function _create_backend_figure(plt::Plot{WinstonBackend})
|
||||
)
|
||||
end
|
||||
|
||||
copy_remove(plotattributes::KW, s::Symbol) = delete!(copy(plotattributes), s)
|
||||
copy_remove(d::KW, s::Symbol) = delete!(copy(d), s)
|
||||
|
||||
function addRegressionLineWinston(plotattributes::KW, wplt)
|
||||
xs, ys = regressionXY(plotattributes[:x], plotattributes[:y])
|
||||
function addRegressionLineWinston(d::KW, wplt)
|
||||
xs, ys = regressionXY(d[:x], d[:y])
|
||||
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
|
||||
end
|
||||
|
||||
@@ -93,22 +93,22 @@ function getWinstonItems(plt::Plot)
|
||||
end
|
||||
|
||||
function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
||||
plotattributes = series.plotattributes
|
||||
d = series.d
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
# until we call it normally, do the hack
|
||||
if plotattributes[:seriestype] == :bar
|
||||
plotattributes = barHack(;plotattributes...)
|
||||
if d[:seriestype] == :bar
|
||||
d = barHack(;d...)
|
||||
end
|
||||
|
||||
|
||||
e = KW()
|
||||
e[:color] = getColor(plotattributes[:linecolor])
|
||||
e[:linewidth] = plotattributes[:linewidth]
|
||||
e[:kind] = winston_linestyle[plotattributes[:linestyle]]
|
||||
e[:symbolkind] = winston_marker[plotattributes[:markershape]]
|
||||
e[:color] = getColor(d[:linecolor])
|
||||
e[:linewidth] = d[:linewidth]
|
||||
e[:kind] = winston_linestyle[d[:linestyle]]
|
||||
e[:symbolkind] = winston_marker[d[:markershape]]
|
||||
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
|
||||
e[:symbolsize] = plotattributes[:markersize] / 5
|
||||
e[:symbolsize] = d[:markersize] / 5
|
||||
|
||||
# pos # (Int,Int), move the enclosing window to this position
|
||||
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
||||
@@ -116,69 +116,69 @@ function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
||||
|
||||
|
||||
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
|
||||
if plotattributes[:seriestype] == :none
|
||||
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
|
||||
if d[:seriestype] == :none
|
||||
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
|
||||
|
||||
elseif plotattributes[:seriestype] == :path
|
||||
x, y = plotattributes[:x], plotattributes[:y]
|
||||
elseif d[:seriestype] == :path
|
||||
x, y = d[:x], d[:y]
|
||||
Winston.add(wplt, Winston.Curve(x, y; e...))
|
||||
|
||||
fillrange = plotattributes[:fillrange]
|
||||
fillrange = d[:fillrange]
|
||||
if fillrange != nothing
|
||||
if isa(fillrange, AbstractVector)
|
||||
y2 = fillrange
|
||||
else
|
||||
y2 = Float64[fillrange for yi in y]
|
||||
end
|
||||
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(plotattributes[:fillcolor])))
|
||||
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(d[:fillcolor])))
|
||||
end
|
||||
|
||||
elseif plotattributes[:seriestype] == :scatter
|
||||
if plotattributes[:markershape] == :none
|
||||
plotattributes[:markershape] = :circle
|
||||
elseif d[:seriestype] == :scatter
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# elseif plotattributes[:seriestype] == :step
|
||||
# elseif d[:seriestype] == :step
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif plotattributes[:seriestype] == :stepinverted
|
||||
# elseif d[:seriestype] == :stepinverted
|
||||
# fn = Winston.XXX
|
||||
|
||||
elseif plotattributes[:seriestype] == :sticks
|
||||
Winston.add(wplt, Winston.Stems(plotattributes[:x], plotattributes[:y]; e...))
|
||||
elseif d[:seriestype] == :sticks
|
||||
Winston.add(wplt, Winston.Stems(d[:x], d[:y]; e...))
|
||||
|
||||
# elseif plotattributes[:seriestype] == :dots
|
||||
# elseif d[:seriestype] == :dots
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif plotattributes[:seriestype] == :histogram2d
|
||||
# elseif d[:seriestype] == :histogram2d
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif plotattributes[:seriestype] == :hexbin
|
||||
# elseif d[:seriestype] == :hexbin
|
||||
# fn = Winston.XXX
|
||||
|
||||
elseif plotattributes[:seriestype] == :histogram
|
||||
hst = hist(plotattributes[:y], plotattributes[:bins])
|
||||
elseif d[:seriestype] == :histogram
|
||||
hst = hist(d[:y], d[:bins])
|
||||
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
|
||||
|
||||
# elseif plotattributes[:seriestype] == :bar
|
||||
# elseif d[:seriestype] == :bar
|
||||
# # fn = Winston.XXX
|
||||
|
||||
else
|
||||
error("seriestype $(plotattributes[:seriestype]) not supported by Winston.")
|
||||
error("seriestype $(d[:seriestype]) not supported by Winston.")
|
||||
|
||||
end
|
||||
|
||||
|
||||
# markershape
|
||||
if plotattributes[:markershape] != :none
|
||||
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
|
||||
if d[:markershape] != :none
|
||||
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
|
||||
end
|
||||
|
||||
|
||||
# optionally add a regression line
|
||||
plotattributes[:smooth] && plotattributes[:seriestype] != :histogram && addRegressionLineWinston(plotattributes, wplt)
|
||||
d[:smooth] && d[:seriestype] != :histogram && addRegressionLineWinston(d, wplt)
|
||||
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# push!(plt.seriesargs, d)
|
||||
# plt
|
||||
end
|
||||
|
||||
@@ -192,17 +192,17 @@ const _winstonNames = KW(
|
||||
:yscale => :ylog,
|
||||
)
|
||||
|
||||
function _update_plot_object(plt::Plot{WinstonBackend}, plotattributes::KW)
|
||||
function _update_plot_object(plt::Plot{WinstonBackend}, d::KW)
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
for k in (:xguide, :yguide, :title, :xlims, :ylims)
|
||||
if haskey(plotattributes, k)
|
||||
Winston.setattr(wplt, string(get(_winstonNames, k, k)), plotattributes[k])
|
||||
if haskey(d, k)
|
||||
Winston.setattr(wplt, string(get(_winstonNames, k, k)), d[k])
|
||||
end
|
||||
end
|
||||
|
||||
for k in (:xscale, :yscale)
|
||||
if haskey(plotattributes, k)
|
||||
islogscale = plotattributes[k] == :log10
|
||||
if haskey(d, k)
|
||||
islogscale = d[k] == :log10
|
||||
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -120,7 +120,7 @@ struct ColorGradient <: ColorScheme
|
||||
|
||||
# # otherwise interpolate evenly between the minval and maxval
|
||||
# minval, maxval = minimum(vals), maximum(vals)
|
||||
# vs = Float64[interpolate(minval, maxval, w) for w in range(0, stop = 1, length = length(cs))]
|
||||
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
|
||||
# new(convertColor(cs,alpha), vs)
|
||||
|
||||
# interpolate the colors for each value
|
||||
@@ -147,7 +147,7 @@ function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
|
||||
ColorGradient(cs, vals; kw...)
|
||||
end
|
||||
|
||||
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
|
||||
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
|
||||
# ColorGradient(map(convertColor, cs), vals; kw...)
|
||||
# end
|
||||
|
||||
|
||||
@@ -7,22 +7,22 @@
|
||||
|
||||
const FuncOrFuncs = Union{Function, AVec{Function}}
|
||||
|
||||
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(plotattributes, :seriestype, :none))
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
|
||||
convertToAnyVector(v::Nothing, d::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, plotattributes::KW)
|
||||
if all3D(plotattributes)
|
||||
function convertToAnyVector(v::AMat, d::KW)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
@@ -30,30 +30,30 @@ function convertToAnyVector(v::AMat, plotattributes::KW)
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
|
||||
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
|
||||
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
|
||||
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, plotattributes::KW)
|
||||
function convertToAnyVector(v::AVec, d::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
|
||||
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
|
||||
|
||||
|
||||
function convertToAnyVector(args...)
|
||||
|
||||
+10
-13
@@ -52,7 +52,7 @@ the `z` argument to turn on series gradients.
|
||||
[:(begin
|
||||
y = rand(100)
|
||||
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=0, α=0.6)
|
||||
scatter!(y, zcolor=abs.(y.-0.5), m=(:heat,0.8,Plots.stroke(1,:green)), ms=10*abs.(y.-0.5).+4,
|
||||
scatter!(y, zcolor=abs.(y.-0.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y.-0.5).+4,
|
||||
lab="grad")
|
||||
end)]
|
||||
),
|
||||
@@ -66,7 +66,6 @@ the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`
|
||||
`yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`
|
||||
""",
|
||||
[:(begin
|
||||
using Statistics
|
||||
y = rand(20,3)
|
||||
plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2),
|
||||
leg=false)
|
||||
@@ -86,8 +85,8 @@ yaxis!("YLABEL", :log10)
|
||||
PlotExample("Images",
|
||||
"Plot an image. y-axis is set to flipped",
|
||||
[:(begin
|
||||
import FileIO, PlotReferenceImages
|
||||
img = FileIO.load(joinpath(dirname(pathof(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)]
|
||||
),
|
||||
@@ -103,7 +102,7 @@ series.
|
||||
""",
|
||||
[:(begin
|
||||
ys = Vector[rand(10), rand(20)]
|
||||
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,Plots.stroke(3,:gray)))
|
||||
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,stroke(3,:gray)))
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -203,8 +202,7 @@ plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbo
|
||||
PlotExample("",
|
||||
"",
|
||||
[:(begin
|
||||
using Random
|
||||
Random.seed!(111)
|
||||
Random.srand(111)
|
||||
plot!(Plots.fakedata(100,10))
|
||||
end)]
|
||||
),
|
||||
@@ -297,7 +295,7 @@ PlotExample("3D",
|
||||
x = ts .* map(cos,ts)
|
||||
y = 0.1ts .* map(sin,ts)
|
||||
z = 1:n
|
||||
plot(x, y, z, zcolor=reverse(z), m=(10,0.8,:blues,Plots.stroke(0)), leg=false, cbar=true, w=5)
|
||||
plot(x, y, z, zcolor=reverse(z), m=(10,0.8,:blues,stroke(0)), leg=false, cbar=true, w=5)
|
||||
plot!(zeros(n),zeros(n),1:n, w=10)
|
||||
end)]
|
||||
),
|
||||
@@ -384,9 +382,8 @@ various different nonzero values, a colorbar is added. The colorbar can be disab
|
||||
`legend = nothing`.
|
||||
""",
|
||||
[:(begin
|
||||
using SparseArrays
|
||||
a = spdiagm(0 => ones(50), 1 => ones(49), -1 => ones(49), 10 => ones(40), -10 => ones(40))
|
||||
b = spdiagm(0 => 1:50, 1 => 1:49, -1 => 1:49, 10 => 1:40, -10 => 1:40)
|
||||
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))
|
||||
plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"])
|
||||
end)]
|
||||
),
|
||||
@@ -414,7 +411,7 @@ attribute. The default framestyle is `:axes`.
|
||||
scatter(fill(randn(10), 6), fill(randn(10), 6),
|
||||
framestyle = [:box :semi :origin :zerolines :grid :none],
|
||||
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
|
||||
color = permutedims(1:6), layout = 6, label = "", markerstrokewidth = 0,
|
||||
color = RowVector(1:6), layout = 6, label = "", markerstrokewidth = 0,
|
||||
ticks = -2:2)
|
||||
end)]
|
||||
),
|
||||
@@ -430,7 +427,7 @@ each line segment or marker in the plot.
|
||||
x = t .* cos.(θ)
|
||||
y = t .* sin.(θ)
|
||||
p1 = plot(x, y, line_z=t, linewidth=3, legend=false)
|
||||
p2 = scatter(x, y, marker_z=(x,y)->x+y, color=:bluesreds, legend=false)
|
||||
p2 = scatter(x, y, marker_z=t, color=:bluesreds, legend=false)
|
||||
plot(p1, p2)
|
||||
end)]
|
||||
),
|
||||
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
function __init__()
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
if haskey(Main.PLOTS_DEFAULTS, :theme)
|
||||
theme(Main.PLOTS_DEFAULTS[:theme])
|
||||
end
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
k == :theme || default(k, v)
|
||||
end
|
||||
end
|
||||
pushdisplay(PlotsDisplay())
|
||||
|
||||
atreplinit(i -> begin
|
||||
if PlotDisplay() in Base.Multimedia.displays
|
||||
popdisplay(PlotsDisplay())
|
||||
end
|
||||
pushdisplay(PlotsDisplay())
|
||||
end)
|
||||
|
||||
include(joinpath(@__DIR__, "backends", "plotly.jl"))
|
||||
include(joinpath(@__DIR__, "backends", "gr.jl"))
|
||||
include(joinpath(@__DIR__, "backends", "web.jl"))
|
||||
|
||||
@require GLVisualize = "4086de5b-f4b6-55f3-abb0-b8c73827585f" include(joinpath(@__DIR__, "backends", "glvisualize.jl"))
|
||||
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
|
||||
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
|
||||
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
|
||||
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" include(joinpath(@__DIR__, "backends", "plotlyjs.jl"))
|
||||
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl"))
|
||||
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl"))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# IJulia
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
|
||||
if IJulia.inited
|
||||
|
||||
"""
|
||||
Add extra jupyter mimetypes to display_dict based on the plot backed.
|
||||
|
||||
The default is nothing, except for plotly based backends, where it
|
||||
adds data for `application/vnd.plotly.v1+json` that is used in
|
||||
frontends like jupyterlab and nteract.
|
||||
"""
|
||||
_extra_mime_info!(plt::Plot, out::Dict) = out
|
||||
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
|
||||
out
|
||||
end
|
||||
|
||||
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
output_type = Symbol(plt.attr[:html_output_format])
|
||||
if output_type == :auto
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
out = Dict()
|
||||
if output_type == :txt
|
||||
mime = "text/plain"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :png
|
||||
mime = "image/png"
|
||||
out[mime] = base64encode(show, MIME(mime), plt)
|
||||
elseif output_type == :svg
|
||||
mime = "image/svg+xml"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :html
|
||||
mime = "text/html"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
else
|
||||
error("Unsupported output type $output_type")
|
||||
end
|
||||
_extra_mime_info!(plt, out)
|
||||
out
|
||||
end
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
end
|
||||
end
|
||||
end
|
||||
+7
-7
@@ -5,8 +5,8 @@ to_pixels(m::AbsoluteLength) = m.value / 0.254
|
||||
|
||||
const _cbar_width = 5mm
|
||||
|
||||
#Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
|
||||
#Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
|
||||
Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
|
||||
Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
|
||||
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
|
||||
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
|
||||
Base.zero(::Type{typeof(mm)}) = 0mm
|
||||
@@ -147,7 +147,7 @@ function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
|
||||
elseif oarg in (:top, :bottom, :vcenter)
|
||||
origver = oarg
|
||||
else
|
||||
@warn("Unused origin arg in bbox construction: $oarg")
|
||||
warn("Unused origin arg in bbox construction: $oarg")
|
||||
end
|
||||
end
|
||||
bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver)
|
||||
@@ -464,12 +464,12 @@ end
|
||||
# constructors
|
||||
|
||||
# pass the layout arg through
|
||||
function layout_args(plotattributes::KW)
|
||||
layout_args(get(plotattributes, :layout, default(:layout)))
|
||||
function layout_args(d::KW)
|
||||
layout_args(get(d, :layout, default(:layout)))
|
||||
end
|
||||
|
||||
function layout_args(plotattributes::KW, n_override::Integer)
|
||||
layout, n = layout_args(get(plotattributes, :layout, n_override))
|
||||
function layout_args(d::KW, n_override::Integer)
|
||||
layout, n = layout_args(get(d, :layout, n_override))
|
||||
if n != n_override
|
||||
error("When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.")
|
||||
end
|
||||
|
||||
+111
-24
@@ -145,6 +145,11 @@ function Base.display(::PlotsDisplay, plt::Plot)
|
||||
_display(plt)
|
||||
end
|
||||
|
||||
# override the REPL display to open a gui window
|
||||
using REPL
|
||||
Base.display(::REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
|
||||
|
||||
|
||||
_do_plot_show(plt, showval::Bool) = showval && gui(plt)
|
||||
function _do_plot_show(plt, showval::Symbol)
|
||||
showval == :gui && gui(plt)
|
||||
@@ -168,10 +173,10 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
if output_type == :png
|
||||
# @info("writing png to html output")
|
||||
# info("writing png to html output")
|
||||
print(io, "<img src=\"data:image/png;base64,", base64encode(show, MIME("image/png"), plt), "\" />")
|
||||
elseif output_type == :svg
|
||||
# @info("writing svg to html output")
|
||||
# info("writing svg to html output")
|
||||
show(io, MIME("image/svg+xml"), plt)
|
||||
elseif output_type == :txt
|
||||
show(io, MIME("text/plain"), plt)
|
||||
@@ -180,8 +185,8 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
end
|
||||
end
|
||||
|
||||
# delegate showable to _show instead
|
||||
function Base.showable(m::M, plt::P) where {M<:MIME, P<:Plot}
|
||||
# delegate mimewritable (showable on julia 0.7) to _show instead
|
||||
function Base.mimewritable(m::M, plt::P) where {M<:MIME, P<:Plot}
|
||||
return hasmethod(_show, Tuple{IO, M, P})
|
||||
end
|
||||
|
||||
@@ -194,12 +199,8 @@ for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml
|
||||
"application/eps", "application/pdf", "application/postscript",
|
||||
"application/x-tex")
|
||||
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
|
||||
if haskey(io, :juno_plotsize)
|
||||
showjuno(io, m, plt)
|
||||
else
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
end
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -250,26 +251,112 @@ end
|
||||
#
|
||||
# html_output_format("svg")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# IJulia
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
|
||||
if IJulia.inited
|
||||
|
||||
"""
|
||||
Add extra jupyter mimetypes to display_dict based on the plot backed.
|
||||
|
||||
The default is nothing, except for plotly based backends, where it
|
||||
adds data for `application/vnd.plotly.v1+json` that is used in
|
||||
frontends like jupyterlab and nteract.
|
||||
"""
|
||||
_extra_mime_info!(plt::Plot, out::Dict) = out
|
||||
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
|
||||
out
|
||||
end
|
||||
|
||||
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
output_type = Symbol(plt.attr[:html_output_format])
|
||||
if output_type == :auto
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
out = Dict()
|
||||
if output_type == :txt
|
||||
mime = "text/plain"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :png
|
||||
mime = "image/png"
|
||||
out[mime] = base64encode(show, MIME(mime), plt)
|
||||
elseif output_type == :svg
|
||||
mime = "image/svg+xml"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :html
|
||||
mime = "text/html"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
else
|
||||
error("Unsupported output type $output_type")
|
||||
end
|
||||
_extra_mime_info!(plt, out)
|
||||
out
|
||||
end
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Atom PlotPane
|
||||
# ---------------------------------------------------------
|
||||
function showjuno(io::IO, m, plt)
|
||||
sz = plt[:size]
|
||||
dpi = plt[:dpi]
|
||||
thickness_scaling = plt[:thickness_scaling]
|
||||
@require Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" begin
|
||||
import Hiccup, Media
|
||||
|
||||
jsize = get(io, :juno_plotsize, [400, 500])
|
||||
if Juno.isactive()
|
||||
Media.media(Plot, Media.Plot)
|
||||
|
||||
scale = minimum(jsize[i] / sz[i] for i in 1:2)
|
||||
plt[:size] = (s * scale for s in sz)
|
||||
plt[:dpi] = Plots.DPI
|
||||
plt[:thickness_scaling] *= scale
|
||||
function Juno.render(e::Juno.Editor, plt::Plot)
|
||||
Juno.render(e, nothing)
|
||||
end
|
||||
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
# temporarily overwrite size to be Atom.plotsize
|
||||
sz = plt[:size]
|
||||
dpi = plt[:dpi]
|
||||
thickness_scaling = plt[:thickness_scaling]
|
||||
jsize = Juno.plotsize()
|
||||
jsize[1] == 0 && (jsize[1] = 400)
|
||||
jsize[2] == 0 && (jsize[2] = 500)
|
||||
|
||||
plt[:size] = sz
|
||||
plt[:dpi] = dpi
|
||||
plt[:thickness_scaling] = thickness_scaling
|
||||
scale = minimum(jsize[i] / sz[i] for i in 1:2)
|
||||
plt[:size] = (s * scale for s in sz)
|
||||
plt[:dpi] = Plots.DPI
|
||||
plt[:thickness_scaling] *= scale
|
||||
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
|
||||
plt[:size] = sz
|
||||
plt[:dpi] = dpi
|
||||
plt[:thickness_scaling] = thickness_scaling
|
||||
end
|
||||
# special handling for PlotlyJS
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
end
|
||||
else
|
||||
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."
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
|
||||
# special handling for plotly... use PlotsDisplay
|
||||
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."
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+65
-65
@@ -7,44 +7,44 @@ function command_idx(kw_list::AVec{KW}, kw::KW)
|
||||
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
|
||||
end
|
||||
|
||||
function _expand_seriestype_array(plotattributes::KW, args)
|
||||
sts = get(plotattributes, :seriestype, :path)
|
||||
function _expand_seriestype_array(d::KW, args)
|
||||
sts = get(d, :seriestype, :path)
|
||||
if typeof(sts) <: AbstractArray
|
||||
delete!(plotattributes, :seriestype)
|
||||
delete!(d, :seriestype)
|
||||
rd = Vector{RecipeData}(undef, size(sts, 1))
|
||||
for r in 1:size(sts, 1)
|
||||
dc = copy(plotattributes)
|
||||
dc = copy(d)
|
||||
dc[:seriestype] = sts[r:r,:]
|
||||
rd[r] = RecipeData(dc, args)
|
||||
end
|
||||
rd
|
||||
else
|
||||
RecipeData[RecipeData(copy(plotattributes), args)]
|
||||
RecipeData[RecipeData(copy(d), args)]
|
||||
end
|
||||
end
|
||||
|
||||
function _preprocess_args(plotattributes::KW, args, still_to_process::Vector{RecipeData})
|
||||
function _preprocess_args(d::KW, args, still_to_process::Vector{RecipeData})
|
||||
# the grouping mechanism is a recipe on a GroupBy object
|
||||
# we simply add the GroupBy object to the front of the args list to allow
|
||||
# the recipe to be applied
|
||||
if haskey(plotattributes, :group)
|
||||
args = (extractGroupArgs(plotattributes[:group], args...), args...)
|
||||
if haskey(d, :group)
|
||||
args = (extractGroupArgs(d[:group], args...), args...)
|
||||
end
|
||||
|
||||
# if we were passed a vector/matrix of seriestypes and there's more than one row,
|
||||
# we want to duplicate the inputs, once for each seriestype row.
|
||||
if !isempty(args)
|
||||
append!(still_to_process, _expand_seriestype_array(plotattributes, args))
|
||||
append!(still_to_process, _expand_seriestype_array(d, args))
|
||||
end
|
||||
|
||||
# remove subplot and axis args from plotattributes... they will be passed through in the kw_list
|
||||
# remove subplot and axis args from d... they will be passed through in the kw_list
|
||||
if !isempty(args)
|
||||
for (k,v) in plotattributes
|
||||
for (k,v) in d
|
||||
for defdict in (_subplot_defaults,
|
||||
_axis_defaults,
|
||||
_axis_defaults_byletter)
|
||||
if haskey(defdict, k)
|
||||
delete!(plotattributes, k)
|
||||
delete!(d, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -57,9 +57,9 @@ end
|
||||
# user recipes
|
||||
|
||||
|
||||
function _process_userrecipes(plt::Plot, plotattributes::KW, args)
|
||||
function _process_userrecipes(plt::Plot, d::KW, args)
|
||||
still_to_process = RecipeData[]
|
||||
args = _preprocess_args(plotattributes, args, still_to_process)
|
||||
args = _preprocess_args(d, args, still_to_process)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
# we are keeping a stack of series that still need to be processed.
|
||||
@@ -80,20 +80,20 @@ function _process_userrecipes(plt::Plot, plotattributes::KW, args)
|
||||
if isempty(next_series.args)
|
||||
_process_userrecipe(plt, kw_list, next_series)
|
||||
else
|
||||
rd_list = RecipesBase.apply_recipe(next_series.plotattributes, next_series.args...)
|
||||
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
||||
prepend!(still_to_process,rd_list)
|
||||
end
|
||||
end
|
||||
|
||||
# don't allow something else to handle it
|
||||
plotattributes[:smooth] = false
|
||||
d[:smooth] = false
|
||||
kw_list
|
||||
end
|
||||
|
||||
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
|
||||
# when the arg tuple is empty, that means there's nothing left to recursively
|
||||
# process... finish up and add to the kw_list
|
||||
kw = recipedata.plotattributes
|
||||
kw = recipedata.d
|
||||
preprocessArgs!(kw)
|
||||
_preprocess_userrecipe(kw)
|
||||
warnOnUnsupported_scales(plt.backend, kw)
|
||||
@@ -117,12 +117,12 @@ function _preprocess_userrecipe(kw::KW)
|
||||
# map marker_z if it's a Function
|
||||
if isa(get(kw, :marker_z, nothing), Function)
|
||||
# TODO: should this take y and/or z as arguments?
|
||||
kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
|
||||
kw[:marker_z] = map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
|
||||
end
|
||||
|
||||
# map line_z if it's a Function
|
||||
if isa(get(kw, :line_z, nothing), Function)
|
||||
kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : map(kw[:line_z], kw[:x], kw[:y], kw[:z])
|
||||
kw[:line_z] = map(kw[:line_z], kw[:x], kw[:y], kw[:z])
|
||||
end
|
||||
|
||||
# convert a ribbon into a fillrange
|
||||
@@ -183,11 +183,11 @@ function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_pr
|
||||
st = kw[:seriestype] = get(_typeAliases, st, st)
|
||||
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
|
||||
for data in datalist
|
||||
preprocessArgs!(data.plotattributes)
|
||||
if data.plotattributes[:seriestype] == st
|
||||
error("Plot recipe $st returned the same seriestype: $(data.plotattributes)")
|
||||
preprocessArgs!(data.d)
|
||||
if data.d[:seriestype] == st
|
||||
error("Plot recipe $st returned the same seriestype: $(data.d)")
|
||||
end
|
||||
push!(still_to_process, data.plotattributes)
|
||||
push!(still_to_process, data.d)
|
||||
end
|
||||
catch err
|
||||
if isa(err, MethodError)
|
||||
@@ -203,14 +203,14 @@ end
|
||||
# ------------------------------------------------------------------
|
||||
# setup plot and subplot
|
||||
|
||||
function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
||||
function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
# merge in anything meant for the Plot
|
||||
for kw in kw_list, (k,v) in kw
|
||||
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
|
||||
haskey(_plot_defaults, k) && (d[k] = pop!(kw, k))
|
||||
end
|
||||
|
||||
# TODO: init subplots here
|
||||
_update_plot_args(plt, plotattributes)
|
||||
_update_plot_args(plt, d)
|
||||
if !plt.init
|
||||
plt.o = Base.invokelatest(_create_backend_figure, plt)
|
||||
|
||||
@@ -252,7 +252,7 @@ function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
||||
plt[:inset_subplots] = nothing
|
||||
end
|
||||
|
||||
function _subplot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
||||
function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
# we'll keep a map of subplot to an attribute override dict.
|
||||
# Subplot/Axis attributes set by a user/series recipe apply only to the
|
||||
# Subplot object which they belong to.
|
||||
@@ -289,8 +289,8 @@ function _subplot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
|
||||
|
||||
# override subplot/axis args. `sp_attrs` take precendence
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx
|
||||
merge(plotattributes, get(sp_attrs, sp, KW()))
|
||||
attr = if !haskey(d, :subplot) || d[:subplot] == idx
|
||||
merge(d, get(sp_attrs, sp, KW()))
|
||||
else
|
||||
get(sp_attrs, sp, KW())
|
||||
end
|
||||
@@ -303,13 +303,13 @@ end
|
||||
|
||||
# getting ready to add the series... last update to subplot from anything
|
||||
# that might have been added during series recipes
|
||||
function _prepare_subplot(plt::Plot{T}, plotattributes::KW) where T
|
||||
st::Symbol = plotattributes[:seriestype]
|
||||
sp::Subplot{T} = plotattributes[:subplot]
|
||||
function _prepare_subplot(plt::Plot{T}, d::KW) where T
|
||||
st::Symbol = d[:seriestype]
|
||||
sp::Subplot{T} = d[:subplot]
|
||||
sp_idx = get_subplot_index(plt, sp)
|
||||
_update_subplot_args(plt, sp, plotattributes, sp_idx, true)
|
||||
_update_subplot_args(plt, sp, d, sp_idx, true)
|
||||
|
||||
st = _override_seriestype_check(plotattributes, st)
|
||||
st = _override_seriestype_check(d, st)
|
||||
|
||||
# change to a 3d projection for this subplot?
|
||||
if is3d(st)
|
||||
@@ -327,28 +327,28 @@ end
|
||||
# ------------------------------------------------------------------
|
||||
# series types
|
||||
|
||||
function _override_seriestype_check(plotattributes::KW, st::Symbol)
|
||||
function _override_seriestype_check(d::KW, st::Symbol)
|
||||
# do we want to override the series type?
|
||||
if !is3d(st) && !(st in (:contour,:contour3d))
|
||||
z = plotattributes[:z]
|
||||
if !isa(z, Nothing) && (size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
|
||||
z = d[:z]
|
||||
if !isa(z, Nothing) && (size(d[:x]) == size(d[:y]) == size(z))
|
||||
st = (st == :scatter ? :scatter3d : :path3d)
|
||||
plotattributes[:seriestype] = st
|
||||
d[:seriestype] = st
|
||||
end
|
||||
end
|
||||
st
|
||||
end
|
||||
|
||||
function _prepare_annotations(sp::Subplot, plotattributes::KW)
|
||||
function _prepare_annotations(sp::Subplot, d::KW)
|
||||
# strip out series annotations (those which are based on series x/y coords)
|
||||
# and add them to the subplot attr
|
||||
sp_anns = annotations(sp[:annotations])
|
||||
# series_anns = annotations(pop!(plotattributes, :series_annotations, []))
|
||||
# series_anns = annotations(pop!(d, :series_annotations, []))
|
||||
# if isa(series_anns, SeriesAnnotations)
|
||||
# series_anns.x = plotattributes[:x]
|
||||
# series_anns.y = plotattributes[:y]
|
||||
# series_anns.x = d[:x]
|
||||
# series_anns.y = d[:y]
|
||||
# elseif length(series_anns) > 0
|
||||
# x, y = plotattributes[:x], plotattributes[:y]
|
||||
# x, y = d[:x], d[:y]
|
||||
# nx, ny, na = map(length, (x,y,series_anns))
|
||||
# n = max(nx, ny, na)
|
||||
# series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
|
||||
@@ -356,14 +356,14 @@ function _prepare_annotations(sp::Subplot, plotattributes::KW)
|
||||
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
||||
end
|
||||
|
||||
function _expand_subplot_extrema(sp::Subplot, plotattributes::KW, st::Symbol)
|
||||
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||
# adjust extrema and discrete info
|
||||
if st == :image
|
||||
xmin, xmax = ignorenan_extrema(plotattributes[:x]); ymin, ymax = ignorenan_extrema(plotattributes[:y])
|
||||
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
|
||||
expand_extrema!(sp[:xaxis], (xmin, xmax))
|
||||
expand_extrema!(sp[:yaxis], (ymin, ymax))
|
||||
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
|
||||
expand_extrema!(sp, plotattributes)
|
||||
expand_extrema!(sp, d)
|
||||
end
|
||||
# expand for zerolines (axes through origin)
|
||||
if sp[:framestyle] in (:origin, :zerolines)
|
||||
@@ -372,10 +372,10 @@ function _expand_subplot_extrema(sp::Subplot, plotattributes::KW, st::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
function _add_the_series(plt, sp, plotattributes)
|
||||
warnOnUnsupported_args(plt.backend, plotattributes)
|
||||
warnOnUnsupported(plt.backend, plotattributes)
|
||||
series = Series(plotattributes)
|
||||
function _add_the_series(plt, sp, d)
|
||||
warnOnUnsupported_args(plt.backend, d)
|
||||
warnOnUnsupported(plt.backend, d)
|
||||
series = Series(d)
|
||||
push!(plt.series_list, series)
|
||||
push!(sp.series_list, series)
|
||||
_series_added(plt, series)
|
||||
@@ -385,38 +385,38 @@ end
|
||||
|
||||
# this method recursively applies series recipes when the seriestype is not supported
|
||||
# natively by the backend
|
||||
function _process_seriesrecipe(plt::Plot, plotattributes::KW)
|
||||
function _process_seriesrecipe(plt::Plot, d::KW)
|
||||
# replace seriestype aliases
|
||||
st = Symbol(plotattributes[:seriestype])
|
||||
st = plotattributes[:seriestype] = get(_typeAliases, st, st)
|
||||
st = Symbol(d[:seriestype])
|
||||
st = d[:seriestype] = get(_typeAliases, st, st)
|
||||
|
||||
# shapes shouldn't have fillrange set
|
||||
if plotattributes[:seriestype] == :shape
|
||||
plotattributes[:fillrange] = nothing
|
||||
if d[:seriestype] == :shape
|
||||
d[:fillrange] = nothing
|
||||
end
|
||||
|
||||
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
|
||||
if is_seriestype_supported(st)
|
||||
sp = _prepare_subplot(plt, plotattributes)
|
||||
_prepare_annotations(sp, plotattributes)
|
||||
_expand_subplot_extrema(sp, plotattributes, st)
|
||||
_update_series_attributes!(plotattributes, plt, sp)
|
||||
_add_the_series(plt, sp, plotattributes)
|
||||
sp = _prepare_subplot(plt, d)
|
||||
_prepare_annotations(sp, d)
|
||||
_expand_subplot_extrema(sp, d, st)
|
||||
_update_series_attributes!(d, plt, sp)
|
||||
_add_the_series(plt, sp, d)
|
||||
|
||||
else
|
||||
# get a sub list of series for this seriestype
|
||||
datalist = RecipesBase.apply_recipe(plotattributes, Val{st}, plotattributes[:x], plotattributes[:y], plotattributes[:z])
|
||||
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
|
||||
|
||||
# assuming there was no error, recursively apply the series recipes
|
||||
for data in datalist
|
||||
if isa(data, RecipeData)
|
||||
preprocessArgs!(data.plotattributes)
|
||||
if data.plotattributes[:seriestype] == st
|
||||
preprocessArgs!(data.d)
|
||||
if data.d[:seriestype] == st
|
||||
error("The seriestype didn't change in series recipe $st. This will cause a StackOverflow.")
|
||||
end
|
||||
_process_seriesrecipe(plt, data.plotattributes)
|
||||
_process_seriesrecipe(plt, data.d)
|
||||
else
|
||||
@warn("Unhandled recipe: $(data)")
|
||||
warn("Unhandled recipe: $(data)")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
+29
-29
@@ -48,20 +48,20 @@ as a String to look up its docstring; e.g. `plotattr("seriestype")`.
|
||||
"""
|
||||
function plot(args...; kw...)
|
||||
# this creates a new plot with args/kw and sets it to be the current plot
|
||||
plotattributes = KW(kw)
|
||||
preprocessArgs!(plotattributes)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
|
||||
# create an empty Plot then process
|
||||
plt = Plot()
|
||||
# plt.user_attr = plotattributes
|
||||
_plot!(plt, plotattributes, args)
|
||||
# plt.user_attr = d
|
||||
_plot!(plt, d, args)
|
||||
end
|
||||
|
||||
# build a new plot from existing plots
|
||||
# note: we split into plt1 and plts_tail so we can dispatch correctly
|
||||
function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
plotattributes = KW(kw)
|
||||
preprocessArgs!(plotattributes)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
|
||||
# build our plot vector from the args
|
||||
n = length(plts_tail) + 1
|
||||
@@ -72,7 +72,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
end
|
||||
|
||||
# compute the layout
|
||||
layout = layout_args(plotattributes, n)[1]
|
||||
layout = layout_args(d, n)[1]
|
||||
num_sp = sum([length(p.subplots) for p in plts])
|
||||
|
||||
# create a new plot object, with subplot list/map made of existing subplots.
|
||||
@@ -83,21 +83,21 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
# TODO: build the user_attr dict by creating "Any matrices" for the args of each subplot
|
||||
|
||||
# TODO: replace this with proper processing from a merged user_attr KW
|
||||
# update plot args, first with existing plots, then override with plotattributes
|
||||
# update plot args, first with existing plots, then override with d
|
||||
for p in plts
|
||||
_update_plot_args(plt, copy(p.attr))
|
||||
plt.n += p.n
|
||||
end
|
||||
_update_plot_args(plt, plotattributes)
|
||||
_update_plot_args(plt, d)
|
||||
|
||||
# pass new plot to the backend
|
||||
plt.o = _create_backend_figure(plt)
|
||||
plt.init = true
|
||||
|
||||
series_attr = KW()
|
||||
for (k,v) in plotattributes
|
||||
for (k,v) in d
|
||||
if haskey(_series_defaults, k)
|
||||
series_attr[k] = pop!(plotattributes,k)
|
||||
series_attr[k] = pop!(d,k)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -118,8 +118,8 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
sp.plt = plt
|
||||
sp.attr[:subplot_index] = idx
|
||||
for series in serieslist
|
||||
merge!(series.plotattributes, series_attr)
|
||||
_add_defaults!(series.plotattributes, plt, sp, cmdidx)
|
||||
merge!(series.d, series_attr)
|
||||
_add_defaults!(series.d, plt, sp, cmdidx)
|
||||
push!(plt.series_list, series)
|
||||
_series_added(plt, series)
|
||||
cmdidx += 1
|
||||
@@ -128,12 +128,12 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
|
||||
# first apply any args for the subplots
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
_update_subplot_args(plt, sp, plotattributes, idx, false)
|
||||
_update_subplot_args(plt, sp, d, idx, false)
|
||||
end
|
||||
|
||||
# finish up
|
||||
current(plt)
|
||||
_do_plot_show(plt, get(plotattributes, :show, default(:show)))
|
||||
_do_plot_show(plt, get(d, :show, default(:show)))
|
||||
plt
|
||||
end
|
||||
|
||||
@@ -152,10 +152,10 @@ end
|
||||
|
||||
# this adds to a specific plot... most plot commands will flow through here
|
||||
function plot!(plt::Plot, args...; kw...)
|
||||
plotattributes = KW(kw)
|
||||
preprocessArgs!(plotattributes)
|
||||
# merge!(plt.user_attr, plotattributes)
|
||||
_plot!(plt, plotattributes, args)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
# merge!(plt.user_attr, d)
|
||||
_plot!(plt, d, args)
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
@@ -163,8 +163,8 @@ end
|
||||
# this is the core plotting function. recursively apply recipes to build
|
||||
# a list of series KW dicts.
|
||||
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
|
||||
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
||||
plotattributes[:plot_object] = plt
|
||||
function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
d[:plot_object] = plt
|
||||
|
||||
if !isempty(args) && !isdefined(Main, :StatPlots) &&
|
||||
first(split(string(typeof(args[1])), ".")) == "DataFrames"
|
||||
@@ -175,9 +175,9 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
||||
# "USER RECIPES"
|
||||
# --------------------------------
|
||||
|
||||
kw_list = _process_userrecipes(plt, plotattributes, args)
|
||||
kw_list = _process_userrecipes(plt, d, args)
|
||||
|
||||
# @info(1)
|
||||
# info(1)
|
||||
# map(DD, kw_list)
|
||||
|
||||
|
||||
@@ -196,14 +196,14 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
||||
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
|
||||
end
|
||||
|
||||
# @info(2)
|
||||
# info(2)
|
||||
# map(DD, kw_list)
|
||||
|
||||
# --------------------------------
|
||||
# Plot/Subplot/Layout setup
|
||||
# --------------------------------
|
||||
_plot_setup(plt, plotattributes, kw_list)
|
||||
_subplot_setup(plt, plotattributes, kw_list)
|
||||
_plot_setup(plt, d, kw_list)
|
||||
_subplot_setup(plt, d, kw_list)
|
||||
|
||||
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
|
||||
# !!! The next step is to recursively apply series recipes until the backend supports that series type !!!
|
||||
@@ -212,7 +212,7 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
||||
# "SERIES RECIPES"
|
||||
# --------------------------------
|
||||
|
||||
# @info(3)
|
||||
# info(3)
|
||||
# map(DD, kw_list)
|
||||
|
||||
for kw in kw_list
|
||||
@@ -283,11 +283,11 @@ end
|
||||
|
||||
function plot(sp::Subplot, args...; kw...)
|
||||
plt = sp.plt
|
||||
plot(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
|
||||
plot(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
|
||||
end
|
||||
function plot!(sp::Subplot, args...; kw...)
|
||||
plt = sp.plt
|
||||
plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
|
||||
plot!(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
+6
-9
@@ -40,26 +40,23 @@ function plotattr(attribute::AbstractString)
|
||||
error("There is no attribute named $attribute")
|
||||
end
|
||||
|
||||
printnothing(x) = x
|
||||
printnothing(x::Nothing) = "nothing"
|
||||
|
||||
function plotattr(attrtype::Symbol, attribute::AbstractString)
|
||||
in(attrtype, keys(_attribute_defaults)) || ArgumentError("`attrtype` must match one of $(attrtypes())")
|
||||
|
||||
attribute = Symbol(lookup_aliases(attrtype, attribute))
|
||||
|
||||
desc = get(_arg_desc, attribute, "")
|
||||
first_period_idx = findfirst(isequal('.'), desc)
|
||||
first_period_idx = findfirst(desc, '.')
|
||||
typedesc = desc[1:first_period_idx-1]
|
||||
desc = strip(desc[first_period_idx+1:end])
|
||||
als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort
|
||||
als = keys(filter((_,v)->v==attribute, _keyAliases)) |> collect |> sort
|
||||
als = join(map(string,als), ", ")
|
||||
def = _attribute_defaults[attrtype][attribute]
|
||||
|
||||
|
||||
# Looks up the different elements and plots them
|
||||
println("$(printnothing(attribute)) ", typedesc == "" ? "" : "{$(printnothing(typedesc))}", "\n",
|
||||
als == "" ? "" : "$(printnothing(als))\n",
|
||||
"\n$(printnothing(desc))\n",
|
||||
"$(printnothing(attrtype)) attribute, ", def == "" ? "" : " default: $(printnothing(def))")
|
||||
println("$attribute ", typedesc == "" ? "" : "{$typedesc}", "\n",
|
||||
als == "" ? "" : "$als\n",
|
||||
"\n$desc\n",
|
||||
"$(attrtype) attribute, ", def == "" ? "" : " default: $def")
|
||||
end
|
||||
|
||||
+45
-52
@@ -47,7 +47,7 @@ end
|
||||
num_series(x::AMat) = size(x,2)
|
||||
num_series(x) = 1
|
||||
|
||||
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
|
||||
RecipesBase.apply_recipe(d::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -277,14 +277,14 @@ end
|
||||
fr = plotattributes[:fillrange]
|
||||
newfr = fr != nothing ? zeros(0) : nothing
|
||||
newz = z != nothing ? zeros(0) : nothing
|
||||
# lz = plotattributes[:line_z]
|
||||
# lz = d[:line_z]
|
||||
# newlz = lz != nothing ? zeros(0) : nothing
|
||||
|
||||
# for each line segment (point series with no NaNs), convert it into a bezier curve
|
||||
# where the points are the control points of the curve
|
||||
for rng in iter_segments(args...)
|
||||
length(rng) < 2 && continue
|
||||
ts = range(0, stop = 1, length = npoints)
|
||||
ts = linspace(0, 1, npoints)
|
||||
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts))
|
||||
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts))
|
||||
if z != nothing
|
||||
@@ -313,9 +313,9 @@ end
|
||||
end
|
||||
# if lz != nothing
|
||||
# # line_z := newlz
|
||||
# linecolor := (isa(plotattributes[:linecolor], ColorGradient) ? plotattributes[:linecolor] : cgrad())
|
||||
# linecolor := (isa(d[:linecolor], ColorGradient) ? d[:linecolor] : cgrad())
|
||||
# end
|
||||
# Plots.DD(plotattributes)
|
||||
# Plots.DD(d)
|
||||
()
|
||||
end
|
||||
@deps curves path
|
||||
@@ -453,16 +453,16 @@ function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:A
|
||||
w_adj, baseline
|
||||
end
|
||||
|
||||
function _preprocess_barlike(plotattributes, x, y)
|
||||
xscale = get(plotattributes, :xscale, :identity)
|
||||
yscale = get(plotattributes, :yscale, :identity)
|
||||
function _preprocess_barlike(d, x, y)
|
||||
xscale = get(d, :xscale, :identity)
|
||||
yscale = get(d, :yscale, :identity)
|
||||
weights, baseline = _preprocess_binbarlike_weights(float(eltype(y)), y, yscale)
|
||||
x, weights, xscale, yscale, baseline
|
||||
end
|
||||
|
||||
function _preprocess_binlike(plotattributes, x, y)
|
||||
xscale = get(plotattributes, :xscale, :identity)
|
||||
yscale = get(plotattributes, :yscale, :identity)
|
||||
function _preprocess_binlike(d, x, y)
|
||||
xscale = get(d, :xscale, :identity)
|
||||
yscale = get(d, :yscale, :identity)
|
||||
T = float(promote_type(eltype(x), eltype(y)))
|
||||
edge = T.(x)
|
||||
weights, baseline = _preprocess_binbarlike_weights(T, y, yscale)
|
||||
@@ -498,25 +498,21 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
|
||||
log_scale_x = xscale in _logScales
|
||||
log_scale_y = yscale in _logScales
|
||||
|
||||
nbins = length(eachindex(weights))
|
||||
if length(eachindex(edge)) != nbins + 1
|
||||
nbins = length(linearindices(weights))
|
||||
if length(linearindices(edge)) != nbins + 1
|
||||
error("Edge vector must be 1 longer than weight vector")
|
||||
end
|
||||
|
||||
x = eltype(edge)[]
|
||||
y = eltype(weights)[]
|
||||
|
||||
it_tuple_e = iterate(edge)
|
||||
a, it_state_e = it_tuple_e
|
||||
it_tuple_e = iterate(edge, it_state_e)
|
||||
|
||||
it_tuple_w = iterate(weights)
|
||||
|
||||
it_e, it_w = start(edge), start(weights)
|
||||
a, it_e = next(edge, it_e)
|
||||
last_w = eltype(weights)(NaN)
|
||||
|
||||
while it_tuple_e != nothing && it_tuple_w != nothing
|
||||
b, it_state_e = it_tuple_e
|
||||
w, it_state_w = it_tuple_w
|
||||
i = 1
|
||||
while (!done(edge, it_e) && !done(edge, it_e))
|
||||
b, it_e = next(edge, it_e)
|
||||
w, it_w = next(weights, it_w)
|
||||
|
||||
if (log_scale_x && a ≈ 0)
|
||||
a = b/_logScaleBases[xscale]^3
|
||||
@@ -540,9 +536,6 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
|
||||
|
||||
a = b
|
||||
last_w = w
|
||||
|
||||
it_tuple_e = iterate(edge, it_state_e)
|
||||
it_tuple_w = iterate(weights, it_state_w)
|
||||
end
|
||||
if (last_w != baseline)
|
||||
push!(x, a)
|
||||
@@ -586,7 +579,7 @@ end
|
||||
end
|
||||
Plots.@deps stepbins path
|
||||
|
||||
wand_edges(x...) = (@warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
||||
wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
||||
|
||||
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
|
||||
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
|
||||
@@ -626,7 +619,7 @@ _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {
|
||||
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
|
||||
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
|
||||
|
||||
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N, Any}) where {N} =
|
||||
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) where {N} =
|
||||
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
|
||||
|
||||
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
|
||||
@@ -781,11 +774,11 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
# Error Bars
|
||||
|
||||
function error_style!(plotattributes::KW)
|
||||
plotattributes[:seriestype] = :path
|
||||
plotattributes[:linecolor] = plotattributes[:markerstrokecolor]
|
||||
plotattributes[:linewidth] = plotattributes[:markerstrokewidth]
|
||||
plotattributes[:label] = ""
|
||||
function error_style!(d::KW)
|
||||
d[:seriestype] = :path
|
||||
d[:linecolor] = d[:markerstrokecolor]
|
||||
d[:linewidth] = d[:markerstrokewidth]
|
||||
d[:label] = ""
|
||||
end
|
||||
|
||||
# if we're passed a tuple of vectors, convert to a vector of tuples
|
||||
@@ -842,16 +835,16 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
# quiver
|
||||
|
||||
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
|
||||
function quiver_using_arrows(plotattributes::KW)
|
||||
plotattributes[:label] = ""
|
||||
plotattributes[:seriestype] = :path
|
||||
if !isa(plotattributes[:arrow], Arrow)
|
||||
plotattributes[:arrow] = arrow()
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
function quiver_using_arrows(d::KW)
|
||||
d[:label] = ""
|
||||
d[:seriestype] = :path
|
||||
if !isa(d[:arrow], Arrow)
|
||||
d[:arrow] = arrow()
|
||||
end
|
||||
|
||||
velocity = error_zipit(plotattributes[:quiver])
|
||||
xorig, yorig = plotattributes[:x], plotattributes[:y]
|
||||
velocity = error_zipit(d[:quiver])
|
||||
xorig, yorig = d[:x], d[:y]
|
||||
|
||||
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
|
||||
x, y = zeros(0), zeros(0)
|
||||
@@ -877,17 +870,17 @@ function quiver_using_arrows(plotattributes::KW)
|
||||
nanappend!(y, [yi, yi+vy, NaN])
|
||||
end
|
||||
|
||||
plotattributes[:x], plotattributes[:y] = x, y
|
||||
# KW[plotattributes]
|
||||
d[:x], d[:y] = x, y
|
||||
# KW[d]
|
||||
end
|
||||
|
||||
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
|
||||
function quiver_using_hack(plotattributes::KW)
|
||||
plotattributes[:label] = ""
|
||||
plotattributes[:seriestype] = :shape
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
function quiver_using_hack(d::KW)
|
||||
d[:label] = ""
|
||||
d[:seriestype] = :shape
|
||||
|
||||
velocity = error_zipit(plotattributes[:quiver])
|
||||
xorig, yorig = plotattributes[:x], plotattributes[:y]
|
||||
velocity = error_zipit(d[:quiver])
|
||||
xorig, yorig = d[:x], d[:y]
|
||||
|
||||
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
|
||||
pts = P2[]
|
||||
@@ -923,11 +916,11 @@ function quiver_using_hack(plotattributes::KW)
|
||||
nanappend!(pts, P2[p, ppv-U1, ppv-U1+U2, ppv, ppv-U1-U2, ppv-U1])
|
||||
end
|
||||
|
||||
plotattributes[:x], plotattributes[:y] = Plots.unzip(pts[2:end])
|
||||
# KW[plotattributes]
|
||||
d[:x], d[:y] = Plots.unzip(pts[2:end])
|
||||
# KW[d]
|
||||
end
|
||||
|
||||
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
@recipe function f(::Type{Val{:quiver}}, x, y, z)
|
||||
if :arrow in supported_attrs()
|
||||
quiver_using_arrows(plotattributes)
|
||||
|
||||
+36
-36
@@ -8,25 +8,25 @@
|
||||
|
||||
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
|
||||
|
||||
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none))
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(d, :seriestype, :none))
|
||||
|
||||
# unknown
|
||||
convertToAnyVector(x, plotattributes::KW) = error("No user recipe defined for $(typeof(x))")
|
||||
convertToAnyVector(x, d::KW) = error("No user recipe defined for $(typeof(x))")
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
|
||||
convertToAnyVector(v::Nothing, d::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, plotattributes::KW)
|
||||
if all3D(plotattributes)
|
||||
function convertToAnyVector(v::AMat, d::KW)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
@@ -34,33 +34,33 @@ function convertToAnyVector(v::AMat, plotattributes::KW)
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
|
||||
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
|
||||
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
|
||||
|
||||
# volume
|
||||
convertToAnyVector(v::Volume, plotattributes::KW) = Any[v], nothing
|
||||
convertToAnyVector(v::Volume, d::KW) = Any[v], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
|
||||
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
|
||||
|
||||
# # dates
|
||||
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, plotattributes::KW)
|
||||
function convertToAnyVector(v::AVec, d::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
|
||||
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
|
||||
|
||||
|
||||
function convertToAnyVector(args...)
|
||||
@@ -180,14 +180,14 @@ end
|
||||
# this should catch unhandled "series recipes" and error with a nice message
|
||||
@recipe f(::Type{V}, x, y, z) where {V<:Val} = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
|
||||
|
||||
_apply_type_recipe(plotattributes, v) = RecipesBase.apply_recipe(plotattributes, typeof(v), v)[1].args[1]
|
||||
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
|
||||
|
||||
# Handle type recipes when the recipe is defined on the elements.
|
||||
# This sort of recipe should return a pair of functions... one to convert to number,
|
||||
# and one to format tick values.
|
||||
function _apply_type_recipe(plotattributes, v::AbstractArray)
|
||||
function _apply_type_recipe(d, v::AbstractArray)
|
||||
isempty(v) && return Float64[]
|
||||
args = RecipesBase.apply_recipe(plotattributes, typeof(v[1]), v[1])[1].args
|
||||
args = RecipesBase.apply_recipe(d, typeof(v[1]), v[1])[1].args
|
||||
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
|
||||
numfunc, formatter = args
|
||||
Formatted(map(numfunc, v), formatter)
|
||||
@@ -197,13 +197,13 @@ function _apply_type_recipe(plotattributes, v::AbstractArray)
|
||||
end
|
||||
|
||||
# # special handling for Surface... need to properly unwrap and re-wrap
|
||||
# function _apply_type_recipe(plotattributes, v::Surface)
|
||||
# function _apply_type_recipe(d, v::Surface)
|
||||
# T = eltype(v.surf)
|
||||
# @show T
|
||||
# if T <: Integer || T <: AbstractFloat
|
||||
# v
|
||||
# else
|
||||
# ret = _apply_type_recipe(plotattributes, v.surf)
|
||||
# ret = _apply_type_recipe(d, v.surf)
|
||||
# if typeof(ret) <: Formatted
|
||||
# Formatted(Surface(ret.data), ret.formatter)
|
||||
# else
|
||||
@@ -213,7 +213,7 @@ end
|
||||
# end
|
||||
|
||||
# don't do anything for ints or floats
|
||||
_apply_type_recipe(plotattributes, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
|
||||
_apply_type_recipe(d, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
|
||||
|
||||
# handle "type recipes" by converting inputs, and then either re-calling or slicing
|
||||
@recipe function f(x, y, z)
|
||||
@@ -274,11 +274,11 @@ end
|
||||
# # --------------------------------------------------------------------
|
||||
|
||||
# helper function to ensure relevant attributes are wrapped by Surface
|
||||
function wrap_surfaces(plotattributes::KW)
|
||||
if haskey(plotattributes, :fill_z)
|
||||
v = plotattributes[:fill_z]
|
||||
function wrap_surfaces(d::KW)
|
||||
if haskey(d, :fill_z)
|
||||
v = d[:fill_z]
|
||||
if !isa(v, Surface)
|
||||
plotattributes[:fill_z] = Surface(v)
|
||||
d[:fill_z] = Surface(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -428,17 +428,17 @@ end
|
||||
# # 3d line or scatter
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, z::AVec)
|
||||
# st = get(plotattributes, :seriestype, :none)
|
||||
# st = get(d, :seriestype, :none)
|
||||
# if st == :scatter
|
||||
# plotattributes[:seriestype] = :scatter3d
|
||||
# d[:seriestype] = :scatter3d
|
||||
# elseif !is3d(st)
|
||||
# plotattributes[:seriestype] = :path3d
|
||||
# d[:seriestype] = :path3d
|
||||
# end
|
||||
SliceIt, x, y, z
|
||||
end
|
||||
|
||||
@recipe function f(x::AMat, y::AMat, z::AMat)
|
||||
# st = get(plotattributes, :seriestype, :none)
|
||||
# st = get(d, :seriestype, :none)
|
||||
# if size(x) == size(y) == size(z)
|
||||
# if !is3d(st)
|
||||
# seriestype := :path3d
|
||||
@@ -518,7 +518,7 @@ end
|
||||
xs, fs
|
||||
end
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n)
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, linspace(umin, umax, n)
|
||||
|
||||
#
|
||||
# # special handling... 3D parametric function(s)
|
||||
@@ -526,7 +526,7 @@ end
|
||||
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
|
||||
end
|
||||
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
|
||||
fx, fy, fz, range(umin, stop = umax, length = numPoints)
|
||||
fx, fy, fz, linspace(umin, umax, numPoints)
|
||||
end
|
||||
|
||||
#
|
||||
@@ -573,7 +573,7 @@ end
|
||||
# # create a new series, with the label of the group, and an idxfilter (to be applied in slice_and_dice)
|
||||
# # TODO: use @series instead
|
||||
# @show i, glab, groupby.groupIds[i]
|
||||
# di = copy(plotattributes)
|
||||
# di = copy(d)
|
||||
# get!(di, :label, string(glab))
|
||||
# get!(di, :idxfilter, groupby.groupIds[i])
|
||||
# push!(series_list, RecipeData(di, args))
|
||||
@@ -594,12 +594,12 @@ function split_kw(key, val::SeriesAnnotations, indices)
|
||||
end
|
||||
|
||||
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
|
||||
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(undef, length(keys(x_ind)), length(groupby.groupLabels))
|
||||
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
|
||||
fill!(y_mat, def_val)
|
||||
for i in 1:length(groupby.groupLabels)
|
||||
xi = x[groupby.groupIds[i]]
|
||||
yi = y[groupby.groupIds[i]]
|
||||
y_mat[getindex.(Ref(x_ind), xi), i] = yi
|
||||
y_mat[getindex.(x_ind, xi), i] = yi
|
||||
end
|
||||
return y_mat
|
||||
end
|
||||
@@ -636,7 +636,7 @@ group_as_matrix(t) = false
|
||||
x = g.args[1]
|
||||
last_args = g.args[2:end]
|
||||
end
|
||||
x_u = unique(sort(x))
|
||||
x_u = unique(x)
|
||||
x_ind = Dict(zip(x_u, 1:length(x_u)))
|
||||
for (key,val) in plotattributes
|
||||
if splittable_kw(key, val, lengthGroup)
|
||||
|
||||
+4
-4
@@ -34,16 +34,16 @@ bottompad(sp::Subplot) = sp.minpad[4]
|
||||
get_subplot(plt::Plot, sp::Subplot) = sp
|
||||
get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
|
||||
get_subplot(plt::Plot, k) = plt.spmap[k]
|
||||
get_subplot(series::Series) = series.plotattributes[:subplot]
|
||||
get_subplot(series::Series) = series.d[:subplot]
|
||||
|
||||
get_subplot_index(plt::Plot, idx::Integer) = Int(idx)
|
||||
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(x -> x === sp, plt.subplots)
|
||||
|
||||
series_list(sp::Subplot) = sp.series_list # filter(series -> series.plotattributes[:subplot] === sp, sp.plt.series_list)
|
||||
series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
|
||||
function should_add_to_legend(series::Series)
|
||||
series.plotattributes[:primary] && series.plotattributes[:label] != "" &&
|
||||
!(series.plotattributes[:seriestype] in (
|
||||
series.d[:primary] && series.d[:label] != "" &&
|
||||
!(series.d[:seriestype] in (
|
||||
:hexbin,:bins2d,:histogram2d,:hline,:vline,
|
||||
:contour,:contourf,:contour3d,:surface,:wireframe,
|
||||
:heatmap, :pie, :image
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ end
|
||||
|
||||
function _get_defaults(s::Symbol)
|
||||
thm = PlotThemes._themes[s]
|
||||
if :defaults in fieldnames(typeof(thm))
|
||||
if :defaults in fieldnames(thm)
|
||||
return thm.defaults
|
||||
else # old PlotTheme type
|
||||
defaults = KW(
|
||||
@@ -132,7 +132,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
|
||||
f(r) = sin(r) / r
|
||||
_norm(x, y) = norm([x, y])
|
||||
x = y = range(-3π, stop = 3π, length = 30)
|
||||
x = y = linspace(-3π, 3π, 30)
|
||||
z = f.(_norm.(x, y'))
|
||||
wi = 2:3:30
|
||||
|
||||
@@ -152,7 +152,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
end
|
||||
|
||||
n = 100
|
||||
ts = range(0, stop = 10π, length = n)
|
||||
ts = linspace(0, 10π, n)
|
||||
x = ts .* cos.(ts)
|
||||
y = (0.1ts) .* sin.(ts)
|
||||
z = 1:n
|
||||
|
||||
+6
-7
@@ -5,7 +5,6 @@
|
||||
const AVec = AbstractVector
|
||||
const AMat = AbstractMatrix
|
||||
const KW = Dict{Symbol,Any}
|
||||
const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString}
|
||||
|
||||
struct PlotsDisplay <: AbstractDisplay end
|
||||
|
||||
@@ -21,11 +20,11 @@ Base.isempty(wrapper::InputWrapper) = false
|
||||
# -----------------------------------------------------------
|
||||
|
||||
mutable struct Series
|
||||
plotattributes::KW
|
||||
d::KW
|
||||
end
|
||||
|
||||
attr(series::Series, k::Symbol) = series.plotattributes[k]
|
||||
attr!(series::Series, v, k::Symbol) = (series.plotattributes[k] = v)
|
||||
attr(series::Series, k::Symbol) = series.d[k]
|
||||
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
@@ -48,7 +47,7 @@ Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
|
||||
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
|
||||
mutable struct Axis
|
||||
sps::Vector{Subplot}
|
||||
plotattributes::KW
|
||||
d::KW
|
||||
end
|
||||
|
||||
mutable struct Extrema
|
||||
@@ -88,7 +87,7 @@ end
|
||||
|
||||
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
|
||||
Base.length(plt::Plot) = length(plt.subplots)
|
||||
Base.lastindex(plt::Plot) = length(plt)
|
||||
Base.endof(plt::Plot) = length(plt)
|
||||
|
||||
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
|
||||
Base.size(plt::Plot) = size(plt.layout)
|
||||
@@ -99,6 +98,6 @@ Base.ndims(plt::Plot) = 2
|
||||
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
|
||||
|
||||
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
|
||||
Base.lastindex(sp::Subplot) = length(series_list(sp))
|
||||
Base.endof(sp::Subplot) = length(series_list(sp))
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
+119
-104
@@ -19,15 +19,15 @@ A hacky replacement for a histogram when the backend doesn't support histograms
|
||||
Convert it into a bar chart with the appropriate x/y values.
|
||||
"""
|
||||
function histogramHack(; kw...)
|
||||
plotattributes = KW(kw)
|
||||
d = KW(kw)
|
||||
|
||||
# we assume that the y kwarg is set with the data to be binned, and nbins is also defined
|
||||
edges, midpoints, buckets, counts = binData(plotattributes[:y], plotattributes[:bins])
|
||||
plotattributes[:x] = midpoints
|
||||
plotattributes[:y] = float(counts)
|
||||
plotattributes[:seriestype] = :bar
|
||||
plotattributes[:fillrange] = plotattributes[:fillrange] == nothing ? 0.0 : plotattributes[:fillrange]
|
||||
plotattributes
|
||||
edges, midpoints, buckets, counts = binData(d[:y], d[:bins])
|
||||
d[:x] = midpoints
|
||||
d[:y] = float(counts)
|
||||
d[:seriestype] = :bar
|
||||
d[:fillrange] = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
|
||||
d
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -35,10 +35,10 @@ A hacky replacement for a bar graph when the backend doesn't support bars direct
|
||||
Convert it into a line chart with fillrange set.
|
||||
"""
|
||||
function barHack(; kw...)
|
||||
plotattributes = KW(kw)
|
||||
midpoints = plotattributes[:x]
|
||||
heights = plotattributes[:y]
|
||||
fillrange = plotattributes[:fillrange] == nothing ? 0.0 : plotattributes[:fillrange]
|
||||
d = KW(kw)
|
||||
midpoints = d[:x]
|
||||
heights = d[:y]
|
||||
fillrange = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
|
||||
|
||||
# estimate the edges
|
||||
dists = diff(midpoints) * 0.5
|
||||
@@ -62,11 +62,11 @@ function barHack(; kw...)
|
||||
append!(y, [fillrange, heights[i], heights[i], fillrange])
|
||||
end
|
||||
|
||||
plotattributes[:x] = x
|
||||
plotattributes[:y] = y
|
||||
plotattributes[:seriestype] = :path
|
||||
plotattributes[:fillrange] = fillrange
|
||||
plotattributes
|
||||
d[:x] = x
|
||||
d[:y] = y
|
||||
d[:seriestype] = :path
|
||||
d[:fillrange] = fillrange
|
||||
d
|
||||
end
|
||||
|
||||
|
||||
@@ -75,33 +75,33 @@ A hacky replacement for a sticks graph when the backend doesn't support sticks d
|
||||
Convert it into a line chart that traces the sticks, and a scatter that sets markers at the points.
|
||||
"""
|
||||
function sticksHack(; kw...)
|
||||
plotattributesLine = KW(kw)
|
||||
plotattributesScatter = copy(plotattributesLine)
|
||||
dLine = KW(kw)
|
||||
dScatter = copy(dLine)
|
||||
|
||||
# these are the line vertices
|
||||
x = Float64[]
|
||||
y = Float64[]
|
||||
fillrange = plotattributesLine[:fillrange] == nothing ? 0.0 : plotattributesLine[:fillrange]
|
||||
fillrange = dLine[:fillrange] == nothing ? 0.0 : dLine[:fillrange]
|
||||
|
||||
# calculate the vertices
|
||||
yScatter = plotattributesScatter[:y]
|
||||
for (i,xi) in enumerate(plotattributesScatter[:x])
|
||||
yScatter = dScatter[:y]
|
||||
for (i,xi) in enumerate(dScatter[:x])
|
||||
yi = yScatter[i]
|
||||
for j in 1:3 push!(x, xi) end
|
||||
append!(y, [fillrange, yScatter[i], fillrange])
|
||||
end
|
||||
|
||||
# change the line args
|
||||
plotattributesLine[:x] = x
|
||||
plotattributesLine[:y] = y
|
||||
plotattributesLine[:seriestype] = :path
|
||||
plotattributesLine[:markershape] = :none
|
||||
plotattributesLine[:fillrange] = nothing
|
||||
dLine[:x] = x
|
||||
dLine[:y] = y
|
||||
dLine[:seriestype] = :path
|
||||
dLine[:markershape] = :none
|
||||
dLine[:fillrange] = nothing
|
||||
|
||||
# change the scatter args
|
||||
plotattributesScatter[:seriestype] = :none
|
||||
dScatter[:seriestype] = :none
|
||||
|
||||
plotattributesLine, plotattributesScatter
|
||||
dLine, dScatter
|
||||
end
|
||||
|
||||
function regressionXY(x, y)
|
||||
@@ -130,10 +130,10 @@ function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
|
||||
# newz, ColorGradient(colors)
|
||||
end
|
||||
|
||||
function imageHack(plotattributes::KW)
|
||||
function imageHack(d::KW)
|
||||
is_seriestype_supported(:heatmap) || error("Neither :image or :heatmap are supported!")
|
||||
plotattributes[:seriestype] = :heatmap
|
||||
plotattributes[:z], plotattributes[:fillcolor] = replace_image_with_heatmap(plotattributes[:z].surf)
|
||||
d[:seriestype] = :heatmap
|
||||
d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z].surf)
|
||||
end
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -215,12 +215,15 @@ anynan(i::Int, args::Tuple) = any(a -> try isnan(_cycle(a,i)) catch MethodError
|
||||
anynan(istart::Int, iend::Int, args::Tuple) = any(i -> anynan(i, args), istart:iend)
|
||||
allnan(istart::Int, iend::Int, args::Tuple) = all(i -> anynan(i, args), istart:iend)
|
||||
|
||||
function Base.iterate(itr::SegmentsIterator, nextidx::Int = 1)
|
||||
nextidx > itr.n && return nothing
|
||||
if nextidx == 1 && !any(isempty,itr.args) && anynan(1, itr.args)
|
||||
nextidx = 2
|
||||
function Base.start(itr::SegmentsIterator)
|
||||
nextidx = 1
|
||||
if !any(isempty,itr.args) && anynan(1, itr.args)
|
||||
_, nextidx = next(itr, 1)
|
||||
end
|
||||
|
||||
nextidx
|
||||
end
|
||||
Base.done(itr::SegmentsIterator, nextidx::Int) = nextidx > itr.n
|
||||
function Base.next(itr::SegmentsIterator, nextidx::Int)
|
||||
i = istart = iend = nextidx
|
||||
|
||||
# find the next NaN, and iend is the one before
|
||||
@@ -303,7 +306,7 @@ function _expand_limits(lims, x)
|
||||
lims[1] = NaNMath.min(lims[1], e1)
|
||||
lims[2] = NaNMath.max(lims[2], e2)
|
||||
# catch err
|
||||
# @warn(err)
|
||||
# warn(err)
|
||||
catch
|
||||
end
|
||||
nothing
|
||||
@@ -328,16 +331,16 @@ function replaceType(vec, val)
|
||||
push!(vec, val)
|
||||
end
|
||||
|
||||
function replaceAlias!(plotattributes::KW, k::Symbol, aliases::Dict{Symbol,Symbol})
|
||||
function replaceAlias!(d::KW, k::Symbol, aliases::Dict{Symbol,Symbol})
|
||||
if haskey(aliases, k)
|
||||
plotattributes[aliases[k]] = pop!(plotattributes, k)
|
||||
d[aliases[k]] = pop!(d, k)
|
||||
end
|
||||
end
|
||||
|
||||
function replaceAliases!(plotattributes::KW, aliases::Dict{Symbol,Symbol})
|
||||
ks = collect(keys(plotattributes))
|
||||
function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
|
||||
ks = collect(keys(d))
|
||||
for k in ks
|
||||
replaceAlias!(plotattributes, k, aliases)
|
||||
replaceAlias!(d, k, aliases)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -347,7 +350,7 @@ Base.first(c::Colorant) = c
|
||||
Base.first(x::Symbol) = x
|
||||
|
||||
|
||||
sortedkeys(plotattributes::Dict) = sort(collect(keys(plotattributes)))
|
||||
sortedkeys(d::Dict) = sort(collect(keys(d)))
|
||||
|
||||
|
||||
const _scale_base = Dict{Symbol, Real}(
|
||||
@@ -409,8 +412,8 @@ function fakedata(sz...)
|
||||
y
|
||||
end
|
||||
|
||||
isijulia() = :IJulia in nameof.(collect(values(Base.loaded_modules)))
|
||||
isatom() = :Atom in nameof.(collect(values(Base.loaded_modules)))
|
||||
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
|
||||
isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
|
||||
|
||||
function is_installed(pkgstr::AbstractString)
|
||||
try
|
||||
@@ -432,8 +435,8 @@ isscalar(::Any) = false
|
||||
is_2tuple(v) = typeof(v) <: Tuple && length(v) == 2
|
||||
|
||||
|
||||
isvertical(plotattributes::KW) = get(plotattributes, :orientation, :vertical) in (:vertical, :v, :vert)
|
||||
isvertical(series::Series) = isvertical(series.plotattributes)
|
||||
isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
|
||||
isvertical(series::Series) = isvertical(series.d)
|
||||
|
||||
|
||||
ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
|
||||
@@ -492,8 +495,8 @@ end
|
||||
# this is a helper function to determine whether we need to transpose a surface matrix.
|
||||
# it depends on whether the backend matches rows to x (transpose_on_match == true) or vice versa
|
||||
# for example: PyPlot sends rows to y, so transpose_on_match should be true
|
||||
function transpose_z(plotattributes, z, transpose_on_match::Bool = true)
|
||||
if plotattributes[:match_dimensions] == transpose_on_match
|
||||
function transpose_z(d, z, transpose_on_match::Bool = true)
|
||||
if d[:match_dimensions] == transpose_on_match
|
||||
# z'
|
||||
permutedims(z, [2,1])
|
||||
else
|
||||
@@ -617,42 +620,22 @@ function hascolorbar(sp::Subplot)
|
||||
hascbar
|
||||
end
|
||||
|
||||
for comp in (:line, :fill, :marker)
|
||||
|
||||
compcolor = string(comp, :color)
|
||||
get_compcolor = Symbol(:get_, compcolor)
|
||||
comp_z = string(comp, :_z)
|
||||
|
||||
compalpha = string(comp, :alpha)
|
||||
get_compalpha = Symbol(:get_, compalpha)
|
||||
|
||||
@eval begin
|
||||
|
||||
function $get_compcolor(series, cmin::Real, cmax::Real, i::Int = 1)
|
||||
c = series[$Symbol($compcolor)]
|
||||
z = series[$Symbol($comp_z)]
|
||||
if z == nothing
|
||||
isa(c, ColorGradient) ? c : plot_color(_cycle(c, i))
|
||||
else
|
||||
grad = isa(c, ColorGradient) ? c : cgrad()
|
||||
grad[clamp((_cycle(z, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
end
|
||||
end
|
||||
|
||||
$get_compcolor(series, clims, i::Int = 1) = $get_compcolor(series, clims[1], clims[2], i)
|
||||
|
||||
function $get_compcolor(series, i::Int = 1)
|
||||
if series[$Symbol($comp_z)] == nothing
|
||||
$get_compcolor(series, 0, 1, i)
|
||||
else
|
||||
$get_compcolor(series, get_clims(series[:subplot]), i)
|
||||
end
|
||||
end
|
||||
|
||||
$get_compalpha(series, i::Int = 1) = _cycle(series[$Symbol($compalpha)], i)
|
||||
function get_linecolor(series, i::Int = 1)
|
||||
lc = series[:linecolor]
|
||||
lz = series[:line_z]
|
||||
if lz == nothing
|
||||
isa(lc, ColorGradient) ? lc : plot_color(_cycle(lc, i))
|
||||
else
|
||||
cmin, cmax = get_clims(series[:subplot])
|
||||
grad = isa(lc, ColorGradient) ? lc : cgrad()
|
||||
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
end
|
||||
end
|
||||
|
||||
function get_linealpha(series, i::Int = 1)
|
||||
_cycle(series[:linealpha], i)
|
||||
end
|
||||
|
||||
function get_linewidth(series, i::Int = 1)
|
||||
_cycle(series[:linewidth], i)
|
||||
end
|
||||
@@ -661,6 +644,38 @@ function get_linestyle(series, i::Int = 1)
|
||||
_cycle(series[:linestyle], i)
|
||||
end
|
||||
|
||||
function get_fillcolor(series, i::Int = 1)
|
||||
fc = series[:fillcolor]
|
||||
fz = series[:fill_z]
|
||||
if fz == nothing
|
||||
isa(fc, ColorGradient) ? fc : plot_color(_cycle(fc, i))
|
||||
else
|
||||
cmin, cmax = get_clims(series[:subplot])
|
||||
grad = isa(fc, ColorGradient) ? fc : cgrad()
|
||||
grad[clamp((_cycle(fz, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
end
|
||||
end
|
||||
|
||||
function get_fillalpha(series, i::Int = 1)
|
||||
_cycle(series[:fillalpha], i)
|
||||
end
|
||||
|
||||
function get_markercolor(series, i::Int = 1)
|
||||
mc = series[:markercolor]
|
||||
mz = series[:marker_z]
|
||||
if mz == nothing
|
||||
isa(mc, ColorGradient) ? mc : plot_color(_cycle(mc, i))
|
||||
else
|
||||
cmin, cmax = get_clims(series[:subplot])
|
||||
grad = isa(mc, ColorGradient) ? mc : cgrad()
|
||||
grad[clamp((_cycle(mz, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
end
|
||||
end
|
||||
|
||||
function get_markeralpha(series, i::Int = 1)
|
||||
_cycle(series[:markeralpha], i)
|
||||
end
|
||||
|
||||
function get_markerstrokecolor(series, i::Int = 1)
|
||||
msc = series[:markerstrokecolor]
|
||||
isa(msc, ColorGradient) ? msc : _cycle(msc, i)
|
||||
@@ -806,20 +821,20 @@ end
|
||||
debugshow(x) = show(x)
|
||||
debugshow(x::AbstractArray) = print(summary(x))
|
||||
|
||||
function dumpdict(plotattributes::KW, prefix = "", alwaysshow = false)
|
||||
function dumpdict(d::KW, prefix = "", alwaysshow = false)
|
||||
_debugMode.on || alwaysshow || return
|
||||
println()
|
||||
if prefix != ""
|
||||
println(prefix, ":")
|
||||
end
|
||||
for k in sort(collect(keys(plotattributes)))
|
||||
for k in sort(collect(keys(d)))
|
||||
@printf("%14s: ", k)
|
||||
debugshow(plotattributes[k])
|
||||
debugshow(d[k])
|
||||
println()
|
||||
end
|
||||
println()
|
||||
end
|
||||
DD(plotattributes::KW, prefix = "") = dumpdict(plotattributes, prefix, true)
|
||||
DD(d::KW, prefix = "") = dumpdict(d, prefix, true)
|
||||
|
||||
|
||||
function dumpcallstack()
|
||||
@@ -845,25 +860,25 @@ tovec(v::AbstractVector) = v
|
||||
tovec(v::Nothing) = zeros(0)
|
||||
|
||||
function getxy(plt::Plot, i::Integer)
|
||||
plotattributes = plt.series_list[i].plotattributes
|
||||
tovec(plotattributes[:x]), tovec(plotattributes[:y])
|
||||
d = plt.series_list[i].d
|
||||
tovec(d[:x]), tovec(d[:y])
|
||||
end
|
||||
function getxyz(plt::Plot, i::Integer)
|
||||
plotattributes = plt.series_list[i].plotattributes
|
||||
tovec(plotattributes[:x]), tovec(plotattributes[:y]), tovec(plotattributes[:z])
|
||||
d = plt.series_list[i].d
|
||||
tovec(d[:x]), tovec(d[:y]), tovec(d[:z])
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
series = plt.series_list[i]
|
||||
series.plotattributes[:x], series.plotattributes[:y] = xy
|
||||
sp = series.plotattributes[:subplot]
|
||||
series.d[:x], series.d[:y] = xy
|
||||
sp = series.d[:subplot]
|
||||
reset_extrema!(sp)
|
||||
_series_updated(plt, series)
|
||||
end
|
||||
function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z}
|
||||
series = plt.series_list[i]
|
||||
series.plotattributes[:x], series.plotattributes[:y], series.plotattributes[:z] = xyz
|
||||
sp = series.plotattributes[:subplot]
|
||||
series.d[:x], series.d[:y], series.d[:z] = xyz
|
||||
sp = series.d[:subplot]
|
||||
reset_extrema!(sp)
|
||||
_series_updated(plt, series)
|
||||
end
|
||||
@@ -912,13 +927,13 @@ Base.push!(series::Series, xi, yi, zi) = (push_x!(series,xi); push_y!(series,yi)
|
||||
# -------------------------------------------------------
|
||||
|
||||
function attr!(series::Series; kw...)
|
||||
plotattributes = KW(kw)
|
||||
preprocessArgs!(plotattributes)
|
||||
for (k,v) in plotattributes
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
for (k,v) in d
|
||||
if haskey(_series_defaults, k)
|
||||
series[k] = v
|
||||
else
|
||||
@warn("unused key $k in series attr")
|
||||
warn("unused key $k in series attr")
|
||||
end
|
||||
end
|
||||
_series_updated(series[:subplot].plt, series)
|
||||
@@ -926,13 +941,13 @@ function attr!(series::Series; kw...)
|
||||
end
|
||||
|
||||
function attr!(sp::Subplot; kw...)
|
||||
plotattributes = KW(kw)
|
||||
preprocessArgs!(plotattributes)
|
||||
for (k,v) in plotattributes
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
for (k,v) in d
|
||||
if haskey(_subplot_defaults, k)
|
||||
sp[k] = v
|
||||
else
|
||||
@warn("unused key $k in subplot attr")
|
||||
warn("unused key $k in subplot attr")
|
||||
end
|
||||
end
|
||||
sp
|
||||
@@ -1057,9 +1072,9 @@ mm2px(mm::Real) = float(px / MM_PER_PX)
|
||||
|
||||
|
||||
"Smallest x in plot"
|
||||
xmin(plt::Plot) = ignorenan_minimum([ignorenan_minimum(series.plotattributes[:x]) for series in plt.series_list])
|
||||
xmin(plt::Plot) = ignorenan_minimum([ignorenan_minimum(series.d[:x]) for series in plt.series_list])
|
||||
"Largest x in plot"
|
||||
xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.plotattributes[:x]) for series in plt.series_list])
|
||||
xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series in plt.series_list])
|
||||
|
||||
"Extrema of x-values in plot"
|
||||
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
|
||||
@@ -2,9 +2,7 @@ StatPlots
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
FileIO
|
||||
GR 0.31.0
|
||||
RDatasets
|
||||
VisualRegressionTests
|
||||
UnicodePlots
|
||||
LaTeXStrings
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using Pkg
|
||||
|
||||
# need this to use Conda
|
||||
# ENV["PYTHON"] = ""
|
||||
|
||||
to_add = [
|
||||
PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"),
|
||||
# PackageSpec(url="https://github.com/JuliaStats/KernelDensity.jl.git"),
|
||||
PackageSpec(name="PlotUtils", rev="master"),
|
||||
PackageSpec(name="RecipesBase", rev="master"),
|
||||
# PackageSpec(name="Blink", rev="master"),
|
||||
# PackageSpec(name="Rsvg", rev="master"),
|
||||
# PackageSpec(name="PlotlyJS", rev="master"),
|
||||
# PackageSpec(name="VisualRegressionTests", rev="master"),
|
||||
# PackageSpec("PyPlot"),
|
||||
# PackageSpec("InspectDR"),
|
||||
]
|
||||
|
||||
if isinteractive()
|
||||
append!(to_add, [
|
||||
PackageSpec(name="FileIO"),
|
||||
PackageSpec(name="ImageMagick"),
|
||||
PackageSpec(name="UnicodePlots"),
|
||||
PackageSpec(name="VisualRegressionTests"),
|
||||
])
|
||||
end
|
||||
|
||||
Pkg.add(to_add)
|
||||
|
||||
Pkg.build("ImageMagick")
|
||||
# Pkg.build("GR")
|
||||
# Pkg.build("Blink")
|
||||
# import Blink
|
||||
# Blink.AtomShell.install()
|
||||
# Pkg.build("PyPlot")
|
||||
+9
-15
@@ -2,10 +2,6 @@
|
||||
using VisualRegressionTests
|
||||
# using ExamplePlots
|
||||
|
||||
if isinteractive()
|
||||
@eval Main import Gtk
|
||||
end
|
||||
|
||||
# import DataFrames, RDatasets
|
||||
|
||||
# don't let pyplot use a gui... it'll crash
|
||||
@@ -13,14 +9,12 @@ end
|
||||
# ENV["MPLBACKEND"] = "Agg"
|
||||
# try
|
||||
# @eval import PyPlot
|
||||
# @info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
|
||||
# info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
|
||||
# end
|
||||
|
||||
|
||||
using Plots
|
||||
# using StatPlots
|
||||
import PlotReferenceImages
|
||||
using Random
|
||||
using Test
|
||||
|
||||
default(size=(500,300))
|
||||
@@ -29,22 +23,22 @@ 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.17.4"
|
||||
const _current_plots_version = v"0.17.3"
|
||||
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2)
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
Plots._debugMode.on = debug
|
||||
example = Plots._examples[idx]
|
||||
@info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
backend(pkg)
|
||||
backend()
|
||||
|
||||
# ensure consistent results
|
||||
Random.seed!(1234)
|
||||
srand(1234)
|
||||
|
||||
# reference image directory setup
|
||||
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
|
||||
refdir = joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots", string(pkg))
|
||||
refdir = Pkg.dir("PlotReferenceImages", "Plots", string(pkg))
|
||||
fn = "ref$idx.png"
|
||||
|
||||
# firgure out version info
|
||||
@@ -89,7 +83,7 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
|
||||
|
||||
# the test
|
||||
vtest = VisualTest(func, reffn, idx)
|
||||
test_images(vtest, popup=popup, sigma=sigma, tol=tol, newfn = newfn)
|
||||
test_images(vtest, popup=popup, sigma=sigma, eps=eps, newfn = newfn)
|
||||
end
|
||||
|
||||
function image_comparison_facts(pkg::Symbol;
|
||||
@@ -97,11 +91,11 @@ function image_comparison_facts(pkg::Symbol;
|
||||
only = nothing, # limit to these examples (int index)
|
||||
debug = false, # print debug information?
|
||||
sigma = [1,1], # number of pixels to "blur"
|
||||
tol = 1e-2) # acceptable error (percent)
|
||||
eps = 1e-2) # acceptable error (percent)
|
||||
for i in 1:length(Plots._examples)
|
||||
i in skip && continue
|
||||
if only == nothing || i in only
|
||||
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, tol=tol) |> success == true
|
||||
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+10
-11
@@ -1,12 +1,11 @@
|
||||
module PlotsTests
|
||||
|
||||
include("add_packages.jl")
|
||||
include("imgcomp.jl")
|
||||
|
||||
# don't actually show the plots
|
||||
Random.seed!(1234)
|
||||
srand(1234)
|
||||
default(show=false, reuse=true)
|
||||
img_tol = isinteractive() ? 1e-2 : 10e-2
|
||||
img_eps = isinteractive() ? 1e-2 : 10e-2
|
||||
|
||||
@testset "GR" begin
|
||||
ENV["PLOTS_TEST"] = "true"
|
||||
@@ -14,7 +13,7 @@ img_tol = isinteractive() ? 1e-2 : 10e-2
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
|
||||
image_comparison_facts(:gr, eps=img_eps, skip = [25, 30])
|
||||
end
|
||||
|
||||
|
||||
@@ -22,7 +21,7 @@ end
|
||||
# @test pyplot() == Plots.PyPlotBackend()
|
||||
# @test backend() == Plots.PyPlotBackend()
|
||||
#
|
||||
# image_comparison_facts(:pyplot, tol=img_tol)
|
||||
# image_comparison_facts(:pyplot, eps=img_eps)
|
||||
#end
|
||||
|
||||
@testset "UnicodePlots" begin
|
||||
@@ -47,7 +46,7 @@ end
|
||||
# 27, # (polar plots) takes very long / not working
|
||||
# 31, # animation (skipped for speed)
|
||||
# ],
|
||||
# tol=img_tol)
|
||||
# eps=img_eps)
|
||||
# end
|
||||
# end
|
||||
|
||||
@@ -71,7 +70,7 @@ end
|
||||
# 28, # heatmap not defined
|
||||
# 31, # animation
|
||||
# ],
|
||||
# tol=img_tol)
|
||||
# eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
@@ -80,7 +79,7 @@ end
|
||||
# @test backend() == Plots.PlotlyBackend()
|
||||
#
|
||||
# # # until png generation is reliable on OSX, just test on linux
|
||||
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
|
||||
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
@@ -89,7 +88,7 @@ end
|
||||
# @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], tol=img_tol)
|
||||
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
@@ -98,7 +97,7 @@ end
|
||||
# @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], tol=img_tol)
|
||||
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
@@ -111,7 +110,7 @@ end
|
||||
# @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], tol=img_tol)
|
||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using Pkg
|
||||
|
||||
Pkg.add("ImageMagick")
|
||||
Pkg.build("ImageMagick")
|
||||
|
||||
# Pkg.clone("GR")
|
||||
# Pkg.build("GR")
|
||||
|
||||
Pkg.checkout("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
|
||||
|
||||
# Pkg.clone("https://github.com/JuliaStats/KernelDensity.jl.git")
|
||||
|
||||
# Pkg.add("StatPlots")
|
||||
Pkg.checkout("PlotUtils")
|
||||
Pkg.checkout("RecipesBase")
|
||||
|
||||
# Pkg.clone("Blink")
|
||||
# Pkg.build("Blink")
|
||||
# import Blink
|
||||
# Blink.AtomShell.install()
|
||||
# Pkg.add("Rsvg")
|
||||
# Pkg.add("PlotlyJS")
|
||||
|
||||
# Pkg.checkout("RecipesBase")
|
||||
# Pkg.clone("VisualRegressionTests")
|
||||
|
||||
# need this to use Conda
|
||||
# ENV["PYTHON"] = ""
|
||||
# Pkg.add("PyPlot")
|
||||
# Pkg.build("PyPlot")
|
||||
|
||||
# Pkg.add("InspectDR")
|
||||
|
||||
Pkg.test("Plots"; coverage=false)
|
||||
Reference in New Issue
Block a user