Compare commits

..

3 Commits

Author SHA1 Message Date
Josef Heinen b9c9fc615b Update gr.jl 2018-08-01 13:06:55 +02:00
Daniel Schwabeneder 50c62ec48e Merge pull request #1593 from fredrikekre/fe/0.72
small additional fixes for 0.7
2018-07-05 08:14:48 +02:00
Fredrik Ekre b16ced0367 small fixes 2018-07-05 00:19:21 +02:00
49 changed files with 1958 additions and 2087 deletions
-1
View File
@@ -5,4 +5,3 @@
examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js
deps/build.log
+8 -9
View File
@@ -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")'
+1 -38
View File
@@ -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
+2 -1
View File
@@ -3,7 +3,6 @@
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/mkborregaard/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<a href="http://docs.juliaplots.org/latest/" target="_blank"><img src="https://img.shields.io/badge/docs-latest-blue.svg" alt="Latest documentation"></a>
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
<!-- [![Coverage Status](https://coveralls.io/repos/tbreloff/Plots.jl/badge.svg?branch=master)](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).
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+56 -131
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+34 -2
View File
@@ -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
View File
@@ -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
+9 -4
View File
@@ -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
+30 -10
View File
@@ -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))))
+3
View File
@@ -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
View File
@@ -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)
+15 -15
View File
@@ -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
View File
@@ -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
+16 -16
View File
@@ -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)
+55 -55
View File
@@ -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
+40 -40
View File
@@ -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
+2 -2
View File
@@ -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
+14 -14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -2,9 +2,7 @@ StatPlots
Images
ImageMagick
@osx QuartzImageIO
FileIO
GR 0.31.0
RDatasets
VisualRegressionTests
UnicodePlots
LaTeXStrings
-35
View File
@@ -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
View File
@@ -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
View File
@@ -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
+34
View File
@@ -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)