Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 01b9cc92fd | |||
| 7a650d918b | |||
| b6fa4bcda4 |
+3
-2
@@ -2,9 +2,10 @@
|
||||
language: julia
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
- osx
|
||||
julia:
|
||||
- 0.6
|
||||
- release
|
||||
- nightly
|
||||
matrix:
|
||||
allow_failures:
|
||||
- julia: nightly
|
||||
|
||||
@@ -3,208 +3,11 @@
|
||||
|
||||
#### notes on release changes, ongoing development, and future planned work
|
||||
|
||||
- All new development should target 0.12!
|
||||
- Minor version 0.11 is the last one to support Julia 0.5!!
|
||||
- Critical bugfixes only
|
||||
- `backports` branch is for Julia 0.4
|
||||
|
||||
---
|
||||
## (current master)
|
||||
|
||||
## 0.12.2
|
||||
|
||||
- fix an issue with Juno/PlotlyJS compatibility on new installations
|
||||
- fix markers not showing up in seriesrecipes using :scatter
|
||||
- don't use pywrap in the pyplot backend
|
||||
- improve the bottom margin for the gr backend
|
||||
|
||||
## 0.12.1
|
||||
|
||||
- fix deprecation warnings
|
||||
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
|
||||
- drop FactCheck in tests
|
||||
- remove julia 0.5 compliant uses of transpose operator
|
||||
- fix GR heatmap bugs
|
||||
- fix GR guide padding
|
||||
- improve legend markers in GR
|
||||
- add surface alpha for Plotly(JS)
|
||||
- add fillrange to Plotly(JS)
|
||||
- allow usage of Matplotlib 1.5 with PyPlot
|
||||
- fix GLVisualize for julia 0.6
|
||||
- conform to changes in InspectDR
|
||||
|
||||
#### 0.12.0
|
||||
|
||||
- 0.6 only
|
||||
|
||||
#### 0.11.3
|
||||
|
||||
- add HDF5 backend
|
||||
- GR replaces PyPlot as first-choice backend
|
||||
- support for legend position in GR
|
||||
- smaller markers in GR
|
||||
- better viewport size in GR
|
||||
- fix glvisualize support
|
||||
- remove bug with three-argument method of `text`
|
||||
- `legendtitle` attribute added
|
||||
- add test for `spy`
|
||||
|
||||
#### 0.11.0
|
||||
|
||||
- julia 0.6 compatibility
|
||||
- matplotlib 0.2.0 compatibility
|
||||
- add inspectdr backend
|
||||
- improved histogram functionality:
|
||||
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)
|
||||
- support for log scale axes with histograms
|
||||
- support for plotting `StatsBase.Histogram`
|
||||
- allowing bins to be specified as `:sturges`, `:rice`, `:scott` or :fd
|
||||
- allow `normalization` to be specified as :density (for unequal bins) or :pdf (sum to 1)
|
||||
- add a `plotattr` function to access documentation for Plots attribute
|
||||
- add `fill_z` attribute for pyplot
|
||||
- add colorbar_title to plotlyjs
|
||||
- enable standalone window for plotlyjs
|
||||
- improved support for pgfplots, ticks rotation, clims, series_annotations
|
||||
- restore colorbars for GR
|
||||
- better axis labels for heatmap in GR
|
||||
- better marker sizes in GR
|
||||
- fix color representation in GR
|
||||
- update GR legend
|
||||
- fix image bug on GR
|
||||
- fix glvisualize dependencies
|
||||
- set dotted grid lines for pyplot
|
||||
- several improvements to inspectdr
|
||||
- improved tick positions for TimeType x axes
|
||||
- support for improved color gradient capability in PlotUtils
|
||||
- add a showlibrary recipe to display color libraries
|
||||
- add a showgradient recipe to display color gradients
|
||||
- add `vectorfield` as an alias for `quiver`
|
||||
- use `PlotUtils.adaptedgrid` for functions
|
||||
|
||||
|
||||
#### 0.9.5
|
||||
|
||||
- added dependency on PlotThemes
|
||||
- set_theme --> theme
|
||||
- remove Compat from REQUIRE
|
||||
- warning for DataFrames without StatPlots
|
||||
- closeall exported and implemented for gr/pyplot
|
||||
- fix DateTime recipe
|
||||
- reset theme with theme(:none)
|
||||
- fix link_axes! for nested subplots
|
||||
- fix plotly lims for log scale
|
||||
|
||||
#### 0.9.4
|
||||
|
||||
- optimizations surrounding Subplot.series_list
|
||||
- better Atom support, support plotlyjs
|
||||
- gr:
|
||||
- gks_wstype defaults and gr_set_output
|
||||
- heatmap uses GR.drawimage
|
||||
- histogram2d puts NaN for zeros
|
||||
- improved support of NaN in heatmaps
|
||||
- rebuilt spy recipes to output scatters with marker_z set
|
||||
- deprecate png support in plotly... point to plotlyjs
|
||||
- fixes:
|
||||
- axis widen with lims set
|
||||
- reset_extrema, setxyz
|
||||
- bar plot widen
|
||||
- better tick padding
|
||||
- consistent tick rotation
|
||||
- consistent aspect_ratio
|
||||
- pyplot dpi
|
||||
- plotly horizontal bars
|
||||
- handle series attributes when combining subplots
|
||||
- gr images transposed
|
||||
- converted Date/DateTime to new type recipe approach for arrays
|
||||
- issues closed include: #505 #513 #479 #523 #526 #529
|
||||
|
||||
#### 0.9.3
|
||||
|
||||
- support pdf and eps in plotlyjs backend
|
||||
- allow curly after grid: `@layout [a b; grid(4,4){0.8h}]`
|
||||
- add_backend redesign
|
||||
|
||||
#### 0.9.2
|
||||
|
||||
- glvisualize backend (@SimonDanisch)
|
||||
- too much to list! ready for alpha testing
|
||||
- Volume and volume seriestype
|
||||
- Atom: support for PlotPane and proper gui display
|
||||
- gr:
|
||||
- clims
|
||||
- aspect ratio
|
||||
- pgfplots:
|
||||
- fixes for ticks, axes, and more
|
||||
- pyplot:
|
||||
- font families
|
||||
- colorbar guide
|
||||
- pixel marker
|
||||
- unicodeplots
|
||||
- basic support for shapes
|
||||
- improved add_backend
|
||||
- refactor of is_supported methods
|
||||
- element-wise type recipes (see https://github.com/tbreloff/Plots.jl/issues/460#issuecomment-248428908)
|
||||
- several other fixes/improvements
|
||||
|
||||
#### 0.9.1
|
||||
|
||||
- Pkg.dir --> dirname (@tkelman)
|
||||
- `axis = nothing` magic
|
||||
- fixes:
|
||||
- clim for line_z
|
||||
- sticks default range for log scale
|
||||
- rotate method
|
||||
- pyplot heatmap
|
||||
- spurious scale warnings
|
||||
- gr image/alpha
|
||||
- plotly.js path
|
||||
- orientation extrema
|
||||
- bar, reset orientation
|
||||
- switch transpose_z to use permutedims
|
||||
- skinny x/+ markers
|
||||
- ticks in pgfplots
|
||||
- eps in savefig (@anriseth)
|
||||
- add_backend convenience
|
||||
- type recipes for Date/DateTime (@maximsch2)
|
||||
- mirror attribute and twinx convenience
|
||||
- Axis.sp --> Axis.sps
|
||||
- recipe postprocessing for allowing aliases and magic args in recipe bodies
|
||||
|
||||
|
||||
|
||||
#### 0.9.0
|
||||
|
||||
- fixes to cycle
|
||||
- add back single function recipe: `plot!(cos)`
|
||||
- new axis formatter attribute... accepts functions to convert numbers to strings
|
||||
- fix for inset plots
|
||||
- GR:
|
||||
- fillrange fix
|
||||
- annotations fix
|
||||
- force double buffering in display
|
||||
- All new development should target 0.7!
|
||||
|
||||
---
|
||||
|
||||
## 0.8
|
||||
|
||||
#### 0.8.2 (backported bug fixes for julia 0.4)
|
||||
|
||||
- plotly ticks fix
|
||||
- unicodeplots size fix
|
||||
- remove mkdir call in tests
|
||||
|
||||
#### 0.8.1
|
||||
|
||||
- manual drawing of axes/ticks/labels
|
||||
- get_ticks uses optimize_ticks and Showoff
|
||||
- changed PLOTS_DEFAULTS to be a global variable, not ENV key
|
||||
- parameterized Segments for pushing tuples
|
||||
- fix to axis extrema for Bool/nothing
|
||||
- GR:
|
||||
- manually draw 2D axes... fixes several issues and missing features
|
||||
- fontsize fix
|
||||
- PGFPlots: pass axis syle
|
||||
## 0.8 (current master/dev)
|
||||
|
||||
#### 0.8.0
|
||||
|
||||
@@ -401,7 +204,7 @@
|
||||
- z-axis keywords
|
||||
- 3D indexing overhaul: `push!`, `append!` support
|
||||
- matplotlib colormap constants (`:inferno` is the new default colormap for Plots)
|
||||
- `const KW = Dict{Symbol,Any}` used in place of splatting in many places
|
||||
- `typealias KW Dict{Symbol,Any}` used in place of splatting in many places
|
||||
- png generation for plotly backend using wkhtmltoimage
|
||||
- `normalize` and `weights` keywords
|
||||
- background/foreground subcategories for fine-tuning of looks
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Plots
|
||||
|
||||
[](https://travis-ci.org/JuliaPlots/Plots.jl)
|
||||
[](https://travis-ci.org/tbreloff/Plots.jl)
|
||||
[](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
julia 0.6-pre
|
||||
julia 0.4
|
||||
|
||||
RecipesBase 0.2.0
|
||||
PlotUtils 0.4.1
|
||||
PlotThemes 0.1.3
|
||||
RecipesBase
|
||||
PlotUtils
|
||||
Reexport
|
||||
StaticArrays 0.5
|
||||
FixedPointNumbers 0.3
|
||||
Compat
|
||||
FixedSizeArrays
|
||||
Measures
|
||||
Showoff
|
||||
StatsBase 0.14.0
|
||||
JSON
|
||||
NaNMath
|
||||
Requires
|
||||
Contour
|
||||
|
||||
+8
-12
@@ -1,9 +1,11 @@
|
||||
environment:
|
||||
matrix:
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
|
||||
- JULIA_URL: "https://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"
|
||||
# Releases
|
||||
- JULIAVERSION: "stable/win32"
|
||||
- JULIAVERSION: "stable/win64"
|
||||
# Nightlies
|
||||
- JULIAVERSION: "download/win32"
|
||||
- JULIAVERSION: "download/win64"
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
@@ -12,14 +14,8 @@ notifications:
|
||||
on_build_status_changed: false
|
||||
|
||||
install:
|
||||
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
|
||||
# If there's a newer build queued for the same PR, cancel this one
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
# Download most recent Julia Windows binary
|
||||
- ps: (new-object net.webclient).DownloadFile($env:JULIA_URL, "C:\projects\julia-binary.exe")
|
||||
- ps: (new-object net.webclient).DownloadFile($("http://status.julialang.org/"+$env:JULIAVERSION), "C:\projects\julia-binary.exe")
|
||||
# Run installer silently, output to C:\projects\julia
|
||||
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
|
||||
|
||||
@@ -30,4 +26,4 @@ build_script:
|
||||
|
||||
test_script:
|
||||
# - C:\projects\julia\bin\julia -e "Pkg.test(\"Plots\")"
|
||||
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"
|
||||
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"
|
||||
+80
-81
@@ -1,38 +1,46 @@
|
||||
__precompile__(false)
|
||||
|
||||
__precompile__()
|
||||
|
||||
module Plots
|
||||
|
||||
using Compat
|
||||
using Reexport
|
||||
|
||||
import StaticArrays
|
||||
using StaticArrays.FixedSizeArrays
|
||||
|
||||
# @reexport using Colors
|
||||
# using Requires
|
||||
using FixedSizeArrays
|
||||
@reexport using RecipesBase
|
||||
import RecipesBase: plot, animate
|
||||
using Base.Meta
|
||||
@reexport using PlotUtils
|
||||
@reexport using PlotThemes
|
||||
import Showoff
|
||||
import StatsBase
|
||||
|
||||
export
|
||||
AbstractPlot,
|
||||
Plot,
|
||||
Subplot,
|
||||
AbstractLayout,
|
||||
GridLayout,
|
||||
grid,
|
||||
EmptyLayout,
|
||||
bbox,
|
||||
plotarea,
|
||||
@layout,
|
||||
AVec,
|
||||
AMat,
|
||||
KW,
|
||||
|
||||
wrap,
|
||||
theme,
|
||||
set_theme,
|
||||
add_theme,
|
||||
|
||||
plot,
|
||||
plot!,
|
||||
attr!,
|
||||
|
||||
current,
|
||||
default,
|
||||
with,
|
||||
twinx,
|
||||
|
||||
@userplot,
|
||||
@shorthands,
|
||||
|
||||
pie,
|
||||
pie!,
|
||||
@@ -53,43 +61,43 @@ export
|
||||
xaxis!,
|
||||
yaxis!,
|
||||
|
||||
xlims,
|
||||
ylims,
|
||||
zlims,
|
||||
|
||||
savefig,
|
||||
png,
|
||||
gui,
|
||||
inline,
|
||||
closeall,
|
||||
|
||||
backend,
|
||||
backends,
|
||||
backend_name,
|
||||
backend_object,
|
||||
add_backend,
|
||||
aliases,
|
||||
dataframes,
|
||||
|
||||
Shape,
|
||||
text,
|
||||
font,
|
||||
Axis,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
arrow,
|
||||
Segments,
|
||||
Formatted,
|
||||
|
||||
debugplots,
|
||||
|
||||
supported_args,
|
||||
supported_types,
|
||||
supported_styles,
|
||||
supported_markers,
|
||||
is_subplot_supported,
|
||||
|
||||
Animation,
|
||||
frame,
|
||||
gif,
|
||||
mov,
|
||||
mp4,
|
||||
animate,
|
||||
@animate,
|
||||
@gif,
|
||||
|
||||
spy,
|
||||
|
||||
test_examples,
|
||||
iter_segments,
|
||||
coords,
|
||||
@@ -102,38 +110,14 @@ export
|
||||
P2,
|
||||
P3,
|
||||
BezierCurve,
|
||||
|
||||
plotattr
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
|
||||
ignorenan_minimum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.minimum(x)
|
||||
ignorenan_minimum(x) = Base.minimum(x)
|
||||
ignorenan_maximum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.maximum(x)
|
||||
ignorenan_maximum(x) = Base.maximum(x)
|
||||
ignorenan_mean{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.mean(x)
|
||||
ignorenan_mean(x) = Base.mean(x)
|
||||
ignorenan_extrema{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.extrema(x)
|
||||
ignorenan_extrema(x) = Base.extrema(x)
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# to cater for block matrices, Base.transpose is recursive.
|
||||
# This makes it impossible to create row vectors of String and Symbol with the transpose operator.
|
||||
# This solves this issue, internally in Plots at least.
|
||||
|
||||
|
||||
# commented out on the insistence of the METADATA maintainers
|
||||
|
||||
#Base.transpose(x::Symbol) = x
|
||||
#Base.transpose(x::String) = x
|
||||
curve_points,
|
||||
directed_curve
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
import Measures
|
||||
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
|
||||
const BBox = Measures.Absolute2DBox
|
||||
typealias BBox Measures.Absolute2DBox
|
||||
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
|
||||
|
||||
# ---------------------------------------------------------
|
||||
@@ -142,6 +126,7 @@ include("types.jl")
|
||||
include("utils.jl")
|
||||
include("components.jl")
|
||||
include("axes.jl")
|
||||
include("backends.jl")
|
||||
include("args.jl")
|
||||
include("themes.jl")
|
||||
include("plot.jl")
|
||||
@@ -151,21 +136,27 @@ include("layouts.jl")
|
||||
include("subplots.jl")
|
||||
include("recipes.jl")
|
||||
include("animation.jl")
|
||||
include("output.jl")
|
||||
include("examples.jl")
|
||||
include("arg_desc.jl")
|
||||
include("plotattr.jl")
|
||||
include("backends.jl")
|
||||
include("output.jl")
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# define and export shorthand plotting method definitions
|
||||
macro shorthands(funcname::Symbol)
|
||||
funcname2 = Symbol(funcname, "!")
|
||||
esc(quote
|
||||
export $funcname, $funcname2
|
||||
$funcname(args...; kw...) = plot(args...; kw..., seriestype = $(quot(funcname)))
|
||||
$funcname2(args...; kw...) = plot!(args...; kw..., seriestype = $(quot(funcname)))
|
||||
end)
|
||||
end
|
||||
|
||||
@shorthands scatter
|
||||
@shorthands bar
|
||||
@shorthands barh
|
||||
@shorthands histogram
|
||||
@shorthands barhist
|
||||
@shorthands stephist
|
||||
@shorthands scatterhist
|
||||
@shorthands histogram2d
|
||||
@shorthands density
|
||||
@shorthands heatmap
|
||||
@@ -214,37 +205,38 @@ yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
|
||||
let PlotOrSubplot = Union{Plot, Subplot}
|
||||
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
|
||||
ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
|
||||
xlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
|
||||
ylims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
|
||||
zlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...)
|
||||
xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
|
||||
ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
|
||||
zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
|
||||
xticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
|
||||
yticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
|
||||
xticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
|
||||
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
|
||||
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
|
||||
yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
|
||||
xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
|
||||
yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
|
||||
end
|
||||
title!(plt::Plot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
xlabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
|
||||
ylabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
|
||||
xlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
|
||||
ylims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
|
||||
zlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...)
|
||||
xlims!(plt::Plot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
|
||||
ylims!(plt::Plot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
|
||||
zlims!(plt::Plot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
|
||||
xticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
|
||||
yticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
|
||||
xticks!{T<:Real,S<:AbstractString}(plt::Plot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
|
||||
yticks!{T<:Real,S<:AbstractString}(plt::Plot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
|
||||
annotate!(plt::Plot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
annotate!{T<:Tuple}(plt::Plot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
xflip!(plt::Plot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
|
||||
yflip!(plt::Plot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
|
||||
xaxis!(plt::Plot, args...; kw...) = plot!(plt; xaxis = args, kw...)
|
||||
yaxis!(plt::Plot, args...; kw...) = plot!(plt; yaxis = args, kw...)
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
# for compatibility with Requires.jl:
|
||||
@init begin
|
||||
function __init__()
|
||||
setup_ijulia()
|
||||
setup_atom()
|
||||
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
default(k, v)
|
||||
@@ -254,4 +246,11 @@ end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# if VERSION >= v"0.4.0-dev+5512"
|
||||
# include("precompile.jl")
|
||||
# _precompile_()
|
||||
# end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
end # module
|
||||
|
||||
+39
-87
@@ -1,110 +1,62 @@
|
||||
|
||||
immutable Animation
|
||||
dir::String
|
||||
frames::Vector{String}
|
||||
dir::Compat.ASCIIString
|
||||
frames::Vector{Compat.ASCIIString}
|
||||
end
|
||||
|
||||
function Animation()
|
||||
tmpdir = convert(String, mktempdir())
|
||||
Animation(tmpdir, String[])
|
||||
tmpdir = convert(Compat.ASCIIString, mktempdir())
|
||||
Animation(tmpdir, Compat.ASCIIString[])
|
||||
end
|
||||
|
||||
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
png(plt, joinpath(anim.dir, filename))
|
||||
push!(anim.frames, filename)
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
png(plt, joinpath(anim.dir, filename))
|
||||
push!(anim.frames, filename)
|
||||
end
|
||||
|
||||
giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
|
||||
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
|
||||
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
|
||||
|
||||
type FrameIterator
|
||||
itr
|
||||
every::Int
|
||||
kw
|
||||
end
|
||||
FrameIterator(itr; every=1, kw...) = FrameIterator(itr, every, kw)
|
||||
|
||||
"""
|
||||
Animate from an iterator which returns the plot args each iteration.
|
||||
"""
|
||||
function animate(fitr::FrameIterator, fn = giffn(); kw...)
|
||||
anim = Animation()
|
||||
for (i, plotargs) in enumerate(fitr.itr)
|
||||
if mod1(i, fitr.every) == 1
|
||||
plot(wraptuple(plotargs)...; fitr.kw...)
|
||||
frame(anim)
|
||||
end
|
||||
end
|
||||
gif(anim, fn; kw...)
|
||||
end
|
||||
|
||||
# most things will implement this
|
||||
function animate(obj, fn = giffn(); every=1, fps=20, loop=0, kw...)
|
||||
animate(FrameIterator(obj, every, kw), fn; fps=fps, loop=loop)
|
||||
end
|
||||
|
||||
# -----------------------------------------------
|
||||
|
||||
"Wraps the location of an animated gif so that it can be displayed"
|
||||
immutable AnimatedGif
|
||||
filename::String
|
||||
filename::Compat.ASCIIString
|
||||
end
|
||||
|
||||
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
|
||||
function gif(anim::Animation, fn = (isijulia() ? "tmp.gif" : tempname()*".gif"); fps::Integer = 20)
|
||||
fn = abspath(fn)
|
||||
|
||||
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...)
|
||||
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn; kw...)
|
||||
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn; kw...)
|
||||
try
|
||||
|
||||
const _imagemagick_initialized = Ref(false)
|
||||
|
||||
function buildanimation(animdir::AbstractString, fn::AbstractString;
|
||||
fps::Integer = 20, loop::Integer = 0)
|
||||
fn = abspath(fn)
|
||||
try
|
||||
if !_imagemagick_initialized[]
|
||||
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
|
||||
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
|
||||
include(file)
|
||||
end
|
||||
_imagemagick_initialized[] = true
|
||||
end
|
||||
|
||||
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
|
||||
# high quality
|
||||
speed = round(Int, 100 / fps)
|
||||
run(`convert -delay $speed -loop $loop $(joinpath(animdir, "*.png")) -alpha off $fn`)
|
||||
|
||||
catch err
|
||||
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
|
||||
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
|
||||
You may also need to install the imagemagick c++ library through your operating system.
|
||||
Will try ffmpeg, but it's lower quality...)""")
|
||||
|
||||
# low quality
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -y $fn`)
|
||||
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
|
||||
# high quality
|
||||
speed = round(Int, 100 / fps)
|
||||
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
|
||||
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
|
||||
include(file)
|
||||
end
|
||||
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
|
||||
run(`convert -delay $speed -loop 0 $(joinpath(anim.dir, "*.png")) -alpha off $fn`)
|
||||
|
||||
info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
catch err
|
||||
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
|
||||
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`
|
||||
Will try ffmpeg, but it's lower quality...)""")
|
||||
|
||||
# low quality
|
||||
run(`ffmpeg -v 0 -framerate $fps -i $(anim.dir)/%06d.png -y $fn`)
|
||||
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
|
||||
end
|
||||
|
||||
info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
|
||||
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
ext = file_extension(agif.filename)
|
||||
write(io, if ext == "gif"
|
||||
"<img src=\"$(relpath(agif.filename))?$(rand())>\" />"
|
||||
elseif ext in ("mov", "mp4")
|
||||
"<video controls><source src=\"$(relpath(agif.filename))?$(rand())>\" type=\"video/$ext\"></video>"
|
||||
else
|
||||
error("Cannot show animation with extension $ext: $agif")
|
||||
end)
|
||||
function Base.writemime(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
write(io, "<img src=\"$(relpath(agif.filename))?$(rand())>\" />")
|
||||
end
|
||||
|
||||
|
||||
@@ -170,7 +122,7 @@ Example:
|
||||
```
|
||||
"""
|
||||
macro gif(forloop::Expr, args...)
|
||||
_animate(forloop, args...; callgif = true)
|
||||
_animate(forloop, args...; callgif = true)
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -179,13 +131,13 @@ Collect one frame per for-block iteration and return an `Animation` object.
|
||||
Example:
|
||||
|
||||
```
|
||||
p = plot(1)
|
||||
anim = @animate for x=0:0.1:5
|
||||
p = plot(1)
|
||||
anim = @animate for x=0:0.1:5
|
||||
push!(p, 1, sin(x))
|
||||
end
|
||||
gif(anim)
|
||||
end
|
||||
gif(anim)
|
||||
```
|
||||
"""
|
||||
macro animate(forloop::Expr, args...)
|
||||
_animate(forloop, args...)
|
||||
_animate(forloop, args...)
|
||||
end
|
||||
|
||||
+4
-9
@@ -19,9 +19,9 @@ const _arg_desc = KW(
|
||||
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers.",
|
||||
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
|
||||
: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`.",
|
||||
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:seriescolor`.",
|
||||
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto. For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector. For histogram-types, defines the number of bins, or the edges, of the histogram.",
|
||||
: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",
|
||||
@@ -29,7 +29,6 @@ const _arg_desc = KW(
|
||||
: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 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).",
|
||||
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
|
||||
@@ -40,7 +39,7 @@ const _arg_desc = KW(
|
||||
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
|
||||
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
|
||||
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
|
||||
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a PDF with integral of 1) and :density (only normalize in respect to bin sizes).",
|
||||
:normalize => "Bool. Should normalize histogram types? Trying for area == 1.",
|
||||
:weights => "AbstractVector. Used in histogram types for weighted counts.",
|
||||
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
|
||||
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
|
||||
@@ -80,21 +79,19 @@ const _arg_desc = KW(
|
||||
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
|
||||
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
|
||||
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
|
||||
:legendtitle => "String or nothing (default). Sets the legend title.",
|
||||
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
|
||||
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
|
||||
:legendfont => "Font. Font of legend items.",
|
||||
:grid => "Bool. Show the grid lines?",
|
||||
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
|
||||
:projection => "Symbol or String. '3d' or 'polar'",
|
||||
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
|
||||
:aspect_ratio => "Symbol (:equal) or Number (width to height ratio of plot area).",
|
||||
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
|
||||
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
|
||||
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
|
||||
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
|
||||
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
|
||||
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
|
||||
:colorbar_title => "String. Title of colorbar.",
|
||||
|
||||
# axis args
|
||||
:guide => "String. Axis guide (label).",
|
||||
@@ -103,13 +100,11 @@ const _arg_desc = KW(
|
||||
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
|
||||
:rotation => "Number. Degrees rotation of tick labels.",
|
||||
:flip => "Bool. Should we flip (reverse) the axis?",
|
||||
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
|
||||
:tickfont => "Font. Font of axis tick labels.",
|
||||
:guidefont => "Font. Font of axis guide (label).",
|
||||
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
|
||||
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
|
||||
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
|
||||
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
|
||||
:mirror => "Bool. Switch the side of the tick labels (right or top).",
|
||||
|
||||
)
|
||||
|
||||
+75
-183
@@ -31,17 +31,15 @@ const _axesAliases = Dict{Symbol,Symbol}(
|
||||
)
|
||||
|
||||
const _3dTypes = [
|
||||
:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume
|
||||
:path3d, :scatter3d, :surface, :wireframe, :contour3d
|
||||
]
|
||||
const _allTypes = vcat([
|
||||
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
||||
:heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins,
|
||||
:scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d,
|
||||
:density, :bar, :hline, :vline,
|
||||
:heatmap, :hexbin, :histogram, :histogram2d, :histogram3d, :density, :bar, :hline, :vline,
|
||||
:contour, :pie, :shape, :image
|
||||
], _3dTypes)
|
||||
|
||||
const _typeAliases = Dict{Symbol,Symbol}(
|
||||
@compat const _typeAliases = Dict{Symbol,Symbol}(
|
||||
:n => :none,
|
||||
:no => :none,
|
||||
:l => :line,
|
||||
@@ -67,7 +65,6 @@ const _typeAliases = Dict{Symbol,Symbol}(
|
||||
:polygon => :shape,
|
||||
:box => :boxplot,
|
||||
:velocity => :quiver,
|
||||
:vectorfield => :quiver,
|
||||
:gradient => :quiver,
|
||||
:img => :image,
|
||||
:imshow => :image,
|
||||
@@ -80,7 +77,7 @@ const _typeAliases = Dict{Symbol,Symbol}(
|
||||
|
||||
add_non_underscore_aliases!(_typeAliases)
|
||||
|
||||
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins)
|
||||
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :density)
|
||||
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
|
||||
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
|
||||
|
||||
@@ -95,7 +92,7 @@ ispolar(series::Series) = ispolar(series.d[:subplot])
|
||||
# ------------------------------------------------------------
|
||||
|
||||
const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _styleAliases = Dict{Symbol,Symbol}(
|
||||
@compat const _styleAliases = Dict{Symbol,Symbol}(
|
||||
:a => :auto,
|
||||
:s => :solid,
|
||||
:d => :dash,
|
||||
@@ -104,7 +101,7 @@ const _styleAliases = Dict{Symbol,Symbol}(
|
||||
)
|
||||
|
||||
const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes))))
|
||||
const _markerAliases = Dict{Symbol,Symbol}(
|
||||
@compat const _markerAliases = Dict{Symbol,Symbol}(
|
||||
:n => :none,
|
||||
:no => :none,
|
||||
:a => :auto,
|
||||
@@ -126,19 +123,9 @@ const _markerAliases = Dict{Symbol,Symbol}(
|
||||
:dtri => :dtriangle,
|
||||
:downtri => :dtriangle,
|
||||
:downtriangle => :dtriangle,
|
||||
:> => :rtriangle,
|
||||
:rt => :rtriangle,
|
||||
:rtri => :rtriangle,
|
||||
:righttri => :rtriangle,
|
||||
:righttriangle => :rtriangle,
|
||||
:< => :ltriangle,
|
||||
:lt => :ltriangle,
|
||||
:ltri => :ltriangle,
|
||||
:lighttri => :ltriangle,
|
||||
:lighttriangle => :ltriangle,
|
||||
# :+ => :cross,
|
||||
:+ => :cross,
|
||||
:plus => :cross,
|
||||
# :x => :xcross,
|
||||
:x => :xcross,
|
||||
:X => :xcross,
|
||||
:star => :star5,
|
||||
:s => :star5,
|
||||
@@ -156,9 +143,7 @@ const _markerAliases = Dict{Symbol,Symbol}(
|
||||
)
|
||||
|
||||
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
const _logScales = [:ln, :log2, :log10]
|
||||
const _logScaleBases = Dict(:ln => e, :log2 => 2.0, :log10 => 10.0)
|
||||
const _scaleAliases = Dict{Symbol,Symbol}(
|
||||
@compat const _scaleAliases = Dict{Symbol,Symbol}(
|
||||
:none => :identity,
|
||||
:log => :log10,
|
||||
)
|
||||
@@ -180,12 +165,12 @@ const _series_defaults = KW(
|
||||
:markershape => :none,
|
||||
:markercolor => :match,
|
||||
:markeralpha => nothing,
|
||||
:markersize => 4,
|
||||
:markersize => 6,
|
||||
:markerstrokestyle => :solid,
|
||||
:markerstrokewidth => 1,
|
||||
:markerstrokecolor => :match,
|
||||
:markerstrokealpha => nothing,
|
||||
:bins => :auto, # number of bins for hists
|
||||
:bins => 30, # number of bins for hists
|
||||
:smooth => false, # regression line?
|
||||
:group => nothing, # groupby vector
|
||||
:x => nothing,
|
||||
@@ -193,7 +178,6 @@ const _series_defaults = KW(
|
||||
:z => nothing, # depth for contour, surface, etc
|
||||
:marker_z => nothing, # value for color scale
|
||||
:line_z => nothing,
|
||||
:fill_z => nothing,
|
||||
:levels => 15,
|
||||
:orientation => :vertical,
|
||||
:bar_position => :overlay, # for bar plots and histograms: could also be stack (stack up) or dodge (side by side)
|
||||
@@ -210,7 +194,7 @@ const _series_defaults = KW(
|
||||
:match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
|
||||
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
|
||||
:subplot => :auto, # which subplot(s) does this series belong to?
|
||||
:series_annotations => nothing, # a list of annotations which apply to the coordinates of this series
|
||||
:series_annotations => [], # a list of annotations which apply to the coordinates of this series
|
||||
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
|
||||
# one logical series to be broken up (path and markers, for example)
|
||||
:hover => nothing, # text to display when hovering over the data points
|
||||
@@ -251,7 +235,6 @@ const _subplot_defaults = KW(
|
||||
:foreground_color_title => :match, # title color
|
||||
:color_palette => :auto,
|
||||
:legend => :best,
|
||||
:legendtitle => nothing,
|
||||
:colorbar => :legend,
|
||||
:clims => :auto,
|
||||
:legendfont => font(8),
|
||||
@@ -265,7 +248,6 @@ const _subplot_defaults = KW(
|
||||
:right_margin => :match,
|
||||
:bottom_margin => :match,
|
||||
:subplot_index => -1,
|
||||
:colorbar_title => "",
|
||||
)
|
||||
|
||||
const _axis_defaults = KW(
|
||||
@@ -283,8 +265,6 @@ const _axis_defaults = KW(
|
||||
:foreground_color_text => :match, # tick text color,
|
||||
:foreground_color_guide => :match, # guide text color,
|
||||
:discrete_values => [],
|
||||
:formatter => :auto,
|
||||
:mirror => false,
|
||||
)
|
||||
|
||||
const _suppress_warnings = Set{Symbol}([
|
||||
@@ -304,24 +284,22 @@ const _suppress_warnings = Set{Symbol}([
|
||||
# add defaults for the letter versions
|
||||
const _axis_defaults_byletter = KW()
|
||||
for letter in (:x,:y,:z)
|
||||
for k in keys(_axis_defaults)
|
||||
# for k in (
|
||||
# :guide,
|
||||
# :lims,
|
||||
# :ticks,
|
||||
# :scale,
|
||||
# :rotation,
|
||||
# :flip,
|
||||
# :link,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :foreground_color_axis,
|
||||
# :foreground_color_border,
|
||||
# :foreground_color_text,
|
||||
# :foreground_color_guide,
|
||||
# :discrete_values,
|
||||
# :formatter,
|
||||
# )
|
||||
for k in (
|
||||
:guide,
|
||||
:lims,
|
||||
:ticks,
|
||||
:scale,
|
||||
:rotation,
|
||||
:flip,
|
||||
:link,
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:foreground_color_axis,
|
||||
:foreground_color_border,
|
||||
:foreground_color_text,
|
||||
:foreground_color_guide,
|
||||
:discrete_values
|
||||
)
|
||||
_axis_defaults_byletter[Symbol(letter,k)] = :match
|
||||
|
||||
# allow the underscore version too: xguide or x_guide
|
||||
@@ -336,15 +314,11 @@ const _all_defaults = KW[
|
||||
_axis_defaults_byletter
|
||||
]
|
||||
|
||||
# to be able to reset font sizes to initial values
|
||||
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefont].pointsize,
|
||||
:legendfont => _subplot_defaults[:legendfont].pointsize,
|
||||
:tickfont => _axis_defaults[:tickfont].pointsize,
|
||||
:guidefont => _axis_defaults[:guidefont].pointsize)
|
||||
|
||||
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
|
||||
supported_args(::AbstractBackend) = error("supported_args not defined") #_all_args
|
||||
supported_args() = supported_args(backend())
|
||||
|
||||
RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
|
||||
RecipesBase.is_key_supported(k::Symbol) = (k in supported_args())
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -375,16 +349,13 @@ end
|
||||
add_aliases(:seriescolor, :c, :color, :colour)
|
||||
add_aliases(:linecolor, :lc, :lcolor, :lcolour, :linecolour)
|
||||
add_aliases(:markercolor, :mc, :mcolor, :mcolour, :markercolour)
|
||||
add_aliases(:markerstrokecolor, :msc, :mscolor, :mscolour, :markerstrokecolour)
|
||||
add_aliases(:markerstrokewidth, :msw, :mswidth)
|
||||
add_aliases(:markerstokecolor, :msc, :mscolor, :mscolour, :markerstokecolour)
|
||||
add_aliases(:fillcolor, :fc, :fcolor, :fcolour, :fillcolour)
|
||||
|
||||
add_aliases(:background_color, :bg, :bgcolor, :bg_color, :background,
|
||||
:background_colour, :bgcolour, :bg_colour)
|
||||
add_aliases(:background_color_legend, :bg_legend, :bglegend, :bgcolor_legend, :bg_color_legend, :background_legend,
|
||||
:background_colour_legend, :bgcolour_legend, :bg_colour_legend)
|
||||
add_aliases(:background_color_subplot, :bg_subplot, :bgsubplot, :bgcolor_subplot, :bg_color_subplot, :background_subplot,
|
||||
:background_colour_subplot, :bgcolour_subplot, :bg_colour_subplot)
|
||||
add_aliases(:background_color_inside, :bg_inside, :bginside, :bgcolor_inside, :bg_color_inside, :background_inside,
|
||||
:background_colour_inside, :bgcolour_inside, :bg_colour_inside)
|
||||
add_aliases(:background_color_outside, :bg_outside, :bgoutside, :bgcolor_outside, :bg_color_outside, :background_outside,
|
||||
@@ -393,8 +364,6 @@ add_aliases(:foreground_color, :fg, :fgcolor, :fg_color, :foreground,
|
||||
:foreground_colour, :fgcolour, :fg_colour)
|
||||
add_aliases(:foreground_color_legend, :fg_legend, :fglegend, :fgcolor_legend, :fg_color_legend, :foreground_legend,
|
||||
:foreground_colour_legend, :fgcolour_legend, :fg_colour_legend)
|
||||
add_aliases(:foreground_color_subplot, :fg_subplot, :fgsubplot, :fgcolor_subplot, :fg_color_subplot, :foreground_subplot,
|
||||
:foreground_colour_subplot, :fgcolour_subplot, :fg_colour_subplot)
|
||||
add_aliases(:foreground_color_grid, :fg_grid, :fggrid, :fgcolor_grid, :fg_color_grid, :foreground_grid,
|
||||
:foreground_colour_grid, :fgcolour_grid, :fg_colour_grid, :gridcolor)
|
||||
add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_color_title, :foreground_title,
|
||||
@@ -411,7 +380,7 @@ add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_co
|
||||
# alphas
|
||||
add_aliases(:seriesalpha, :alpha, :α, :opacity)
|
||||
add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
|
||||
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
|
||||
add_aliases(:makeralpha, :ma, :malpha, :mα, :makeropacity, :mopacity)
|
||||
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
|
||||
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
|
||||
|
||||
@@ -444,9 +413,7 @@ add_aliases(:zguide, :zlabel, :zlab, :zl)
|
||||
add_aliases(:zlims, :zlim, :zlimit, :zlimits)
|
||||
add_aliases(:zticks, :ztick)
|
||||
add_aliases(:zrotation, :zrot, :zr)
|
||||
add_aliases(:fill_z, :fillz, :fz, :surfacecolor, :surfacecolour, :sc, :surfcolor, :surfcolour)
|
||||
add_aliases(:legend, :leg, :key)
|
||||
add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title)
|
||||
add_aliases(:colorbar, :cb, :cbar, :colorkey)
|
||||
add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits)
|
||||
add_aliases(:smooth, :regression, :reg)
|
||||
@@ -458,14 +425,14 @@ add_aliases(:color_palette, :palette)
|
||||
add_aliases(:overwrite_figure, :clf, :clearfig, :overwrite, :reuse)
|
||||
add_aliases(:xerror, :xerr, :xerrorbar)
|
||||
add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
|
||||
add_aliases(:quiver, :velocity, :quiver2d, :gradient, :vectorfield)
|
||||
add_aliases(:quiver, :velocity, :quiver2d, :gradient)
|
||||
add_aliases(:normalize, :norm, :normed, :normalized)
|
||||
add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio)
|
||||
add_aliases(:match_dimensions, :transpose, :transpose_z)
|
||||
add_aliases(:subplot, :sp, :subplt, :splt)
|
||||
add_aliases(:projection, :proj)
|
||||
add_aliases(:title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment)
|
||||
add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation, :text, :txt, :texts, :txts)
|
||||
add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation)
|
||||
add_aliases(:html_output_format, :format, :fmt, :html_format)
|
||||
add_aliases(:orientation, :direction, :dir)
|
||||
add_aliases(:inset_subplots, :inset, :floating)
|
||||
@@ -486,7 +453,6 @@ end
|
||||
`default(key)` returns the current default value for that key
|
||||
`default(key, value)` sets the current default value for that key
|
||||
`default(; kw...)` will set the current default value for each key/value pair
|
||||
`default(d, key)` returns the key from d if it exists, otherwise `default(key)`
|
||||
"""
|
||||
|
||||
function default(k::Symbol)
|
||||
@@ -523,10 +489,6 @@ function default(; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
function default(d::KW, k::Symbol)
|
||||
get(d, k, default(k))
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -642,7 +604,7 @@ function processFillArg(d::KW, arg)
|
||||
d[:fillrange] = arg
|
||||
end
|
||||
# d[:fillrange] = fr
|
||||
return
|
||||
return
|
||||
end
|
||||
|
||||
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
|
||||
@@ -662,21 +624,6 @@ end
|
||||
function preprocessArgs!(d::KW)
|
||||
replaceAliases!(d, _keyAliases)
|
||||
|
||||
# clear all axis stuff
|
||||
if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
|
||||
d[:ticks] = nothing
|
||||
d[:foreground_color_border] = RGBA(0,0,0,0)
|
||||
d[:grid] = false
|
||||
delete!(d, :axis)
|
||||
end
|
||||
# for letter in (:x, :y, :z)
|
||||
# asym = Symbol(letter, :axis)
|
||||
# if haskey(d, asym) || d[asym] in (:none, nothing, false)
|
||||
# d[Symbol(letter, :ticks)] = nothing
|
||||
# d[Symbol(letter, :foreground_color_border)] = RGBA(0,0,0,0)
|
||||
# end
|
||||
# end
|
||||
|
||||
# handle axis args
|
||||
for letter in (:x, :y, :z)
|
||||
asym = Symbol(letter, :axis)
|
||||
@@ -706,9 +653,6 @@ function preprocessArgs!(d::KW)
|
||||
delete!(d, :marker)
|
||||
if haskey(d, :markershape)
|
||||
d[:markershape] = _replace_markershape(d[:markershape])
|
||||
if d[:markershape] == :none && d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
elseif anymarker
|
||||
d[:markershape_to_add] = :circle # add it after _apply_recipe
|
||||
end
|
||||
@@ -719,18 +663,13 @@ function preprocessArgs!(d::KW)
|
||||
end
|
||||
delete!(d, :fill)
|
||||
|
||||
# handle series annotations
|
||||
if haskey(d, :series_annotations)
|
||||
d[:series_annotations] = series_annotations(wraptuple(d[:series_annotations])...)
|
||||
end
|
||||
|
||||
# convert into strokes and brushes
|
||||
|
||||
if haskey(d, :arrow)
|
||||
a = d[:arrow]
|
||||
d[:arrow] = if a == true
|
||||
arrow()
|
||||
elseif a in (false, nothing, :none)
|
||||
elseif a == false
|
||||
nothing
|
||||
elseif !(typeof(a) <: Arrow)
|
||||
arrow(wraptuple(a)...)
|
||||
@@ -740,9 +679,9 @@ function preprocessArgs!(d::KW)
|
||||
end
|
||||
|
||||
|
||||
# if get(d, :arrow, false) == true
|
||||
# d[:arrow] = arrow()
|
||||
# end
|
||||
if get(d, :arrow, false) == true
|
||||
d[:arrow] = arrow()
|
||||
end
|
||||
|
||||
# legends
|
||||
if haskey(d, :legend)
|
||||
@@ -808,51 +747,43 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
const _already_warned = Dict{Symbol,Set{Symbol}}()
|
||||
const _to_warn = Set{Symbol}()
|
||||
const _already_warned = Set()
|
||||
|
||||
function warnOnUnsupported_args(pkg::AbstractBackend, d::KW)
|
||||
empty!(_to_warn)
|
||||
bend = backend_name(pkg)
|
||||
already_warned = get!(_already_warned, bend, Set{Symbol}())
|
||||
for k in keys(d)
|
||||
is_attr_supported(pkg, k) && continue
|
||||
for k in sortedkeys(d)
|
||||
k in supported_args(pkg) && continue
|
||||
k in _suppress_warnings && continue
|
||||
if d[k] != default(k)
|
||||
k in already_warned || push!(_to_warn, k)
|
||||
end
|
||||
end
|
||||
|
||||
if !isempty(_to_warn)
|
||||
for k in sort(collect(_to_warn))
|
||||
push!(already_warned, k)
|
||||
warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_attrs(pkg))")
|
||||
if !((pkg, k) in _already_warned)
|
||||
push!(_already_warned, (pkg,k))
|
||||
warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_args(pkg))")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# _markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supported_markers(pkg)
|
||||
# _markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
|
||||
# _markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supported_markers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||
|
||||
function warnOnUnsupported(pkg::AbstractBackend, d::KW)
|
||||
if !is_seriestype_supported(pkg, d[:seriestype])
|
||||
warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))")
|
||||
end
|
||||
if !is_style_supported(pkg, d[:linestyle])
|
||||
warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))")
|
||||
end
|
||||
if !is_marker_supported(pkg, d[:markershape])
|
||||
warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))")
|
||||
end
|
||||
(d[:seriestype] == :none
|
||||
|| d[:seriestype] in supported_types(pkg)
|
||||
|| warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supported_types(pkg))"))
|
||||
(d[:linestyle] in supported_styles(pkg)
|
||||
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))"))
|
||||
(d[:markershape] == :none
|
||||
|| _markershape_supported(pkg, d[:markershape])
|
||||
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))"))
|
||||
end
|
||||
|
||||
function warnOnUnsupported_scales(pkg::AbstractBackend, d::KW)
|
||||
for k in (:xscale, :yscale, :zscale, :scale)
|
||||
if haskey(d, k)
|
||||
v = d[k]
|
||||
if !is_scale_supported(pkg, v)
|
||||
warn("scale $v is unsupported with $pkg. Choose from: $(supported_scales(pkg))")
|
||||
v = get(_scaleAliases, v, v)
|
||||
if !(v in supported_scales(pkg))
|
||||
warn("scale $(d[k]) is unsupported with $pkg. Choose from: $(supported_scales(pkg))")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -874,7 +805,6 @@ function convertLegendValue(val::Symbol)
|
||||
end
|
||||
convertLegendValue(val::Bool) = val ? :best : :none
|
||||
convertLegendValue(val::Void) = :none
|
||||
convertLegendValue{S<:Real, T<:Real}(v::Tuple{S,T}) = v
|
||||
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -992,7 +922,7 @@ function Base.getindex(axis::Axis, k::Symbol)
|
||||
v = axis.d[k]
|
||||
if v == :match
|
||||
if haskey(_match_map2, k)
|
||||
axis.sps[1][_match_map2[k]]
|
||||
axis.sp[_match_map2[k]]
|
||||
else
|
||||
axis[_match_map[k]]
|
||||
end
|
||||
@@ -1018,27 +948,6 @@ Base.get(series::Series, k::Symbol, v) = get(series.d, k, v)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
function fg_color(d::KW)
|
||||
fg = default(d, :foreground_color)
|
||||
if fg == :auto
|
||||
bg = plot_color(default(d, :background_color))
|
||||
fg = isdark(bg) ? colorant"white" : colorant"black"
|
||||
else
|
||||
plot_color(fg)
|
||||
end
|
||||
end
|
||||
|
||||
function fg_color_sp(d::KW)
|
||||
fgsp = default(d, :foreground_color_subplot)
|
||||
if fg == :match
|
||||
fg_color(d)
|
||||
else
|
||||
plot_color(fgsp)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# update attr from an input dictionary
|
||||
function _update_plot_args(plt::Plot, d_in::KW)
|
||||
for (k,v) in _plot_defaults
|
||||
@@ -1046,30 +955,21 @@ function _update_plot_args(plt::Plot, d_in::KW)
|
||||
end
|
||||
|
||||
# handle colors
|
||||
d = plt.attr
|
||||
plt[:background_color] = plot_color(d[:background_color])
|
||||
plt[:foreground_color] = fg_color(d)
|
||||
# bg = plot_color(plt.attr[:background_color])
|
||||
# fg = plt.attr[:foreground_color]
|
||||
# if fg == :auto
|
||||
# fg = isdark(bg) ? colorant"white" : colorant"black"
|
||||
# end
|
||||
# plt.attr[:background_color] = bg
|
||||
# plt.attr[:foreground_color] = plot_color(fg)
|
||||
bg = plot_color(plt.attr[:background_color])
|
||||
fg = plt.attr[:foreground_color]
|
||||
if fg == :auto
|
||||
fg = isdark(bg) ? colorant"white" : colorant"black"
|
||||
end
|
||||
plt.attr[:background_color] = bg
|
||||
plt.attr[:foreground_color] = plot_color(fg)
|
||||
color_or_nothing!(plt.attr, :background_color_outside)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
function _update_subplot_periphery(sp::Subplot, anns::AVec)
|
||||
# extend annotations, and ensure we always have a (x,y,PlotText) tuple
|
||||
newanns = vcat(anns, sp[:annotations])
|
||||
for (i,ann) in enumerate(newanns)
|
||||
x,y,tmp = ann
|
||||
ptxt = isa(tmp, PlotText) ? tmp : text(tmp)
|
||||
newanns[i] = (x,y,ptxt)
|
||||
end
|
||||
sp.attr[:annotations] = newanns
|
||||
# extend annotations
|
||||
sp.attr[:annotations] = vcat(anns, sp[:annotations])
|
||||
|
||||
# handle legend/colorbar
|
||||
sp.attr[:legend] = convertLegendValue(sp.attr[:legend])
|
||||
@@ -1133,7 +1033,7 @@ function _update_axis(axis::Axis, d_in::KW, letter::Symbol, subplot_index::Int)
|
||||
end
|
||||
|
||||
# update the axis
|
||||
attr!(axis, args...; kw...)
|
||||
update!(axis, args...; kw...)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1188,8 +1088,6 @@ end
|
||||
function getSeriesRGBColor(c, α, sp::Subplot, n::Int)
|
||||
if c == :auto
|
||||
c = autopick(sp[:color_palette], n)
|
||||
elseif isa(c, Int)
|
||||
c = autopick(sp[:color_palette], c)
|
||||
end
|
||||
plot_color(c, α)
|
||||
end
|
||||
@@ -1217,14 +1115,7 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
end
|
||||
|
||||
# this is how many series belong to this subplot
|
||||
# plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list)
|
||||
plotIndex = 0
|
||||
for series in sp.series_list
|
||||
if series[:primary]
|
||||
plotIndex += 1
|
||||
end
|
||||
end
|
||||
# plotIndex = count(series -> series[:primary], sp.series_list)
|
||||
plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list)
|
||||
if get(d, :primary, true)
|
||||
plotIndex += 1
|
||||
end
|
||||
@@ -1275,7 +1166,7 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
end
|
||||
|
||||
# scatter plots don't have a line, but must have a shape
|
||||
if d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d)
|
||||
if d[:seriestype] in (:scatter, :scatter3d)
|
||||
d[:linewidth] = 0
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :circle
|
||||
@@ -1290,3 +1181,4 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
_replace_linewidth(d)
|
||||
d
|
||||
end
|
||||
|
||||
|
||||
+52
-111
@@ -23,13 +23,13 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
lk = Symbol(letter, k)
|
||||
lv = _axis_defaults_byletter[lk]
|
||||
d[k] = (lv == :match ? v : lv)
|
||||
end
|
||||
end
|
||||
|
||||
# merge!(d, _axis_defaults)
|
||||
d[:discrete_values] = []
|
||||
|
||||
# update the defaults
|
||||
attr!(Axis([sp], d), args...; kw...)
|
||||
update!(Axis(sp, d), args...; kw...)
|
||||
end
|
||||
|
||||
function get_axis(sp::Subplot, letter::Symbol)
|
||||
@@ -73,9 +73,6 @@ function process_axis_arg!(d::KW, arg, letter = "")
|
||||
elseif typeof(arg) <: Number
|
||||
d[Symbol(letter,:rotation)] = arg
|
||||
|
||||
elseif typeof(arg) <: Function
|
||||
d[Symbol(letter,:formatter)] = arg
|
||||
|
||||
else
|
||||
warn("Skipped $(letter)axis arg $arg")
|
||||
|
||||
@@ -83,7 +80,7 @@ function process_axis_arg!(d::KW, arg, letter = "")
|
||||
end
|
||||
|
||||
# update an Axis object with magic args and keywords
|
||||
function attr!(axis::Axis, args...; kw...)
|
||||
function update!(axis::Axis, args...; kw...)
|
||||
# first process args
|
||||
d = axis.d
|
||||
for arg in args
|
||||
@@ -118,7 +115,7 @@ 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))
|
||||
Base.extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
|
||||
|
||||
|
||||
const _scale_funcs = Dict{Symbol,Function}(
|
||||
@@ -132,12 +129,6 @@ const _inv_scale_funcs = Dict{Symbol,Function}(
|
||||
:ln => exp,
|
||||
)
|
||||
|
||||
# const _label_func = Dict{Symbol,Function}(
|
||||
# :log10 => x -> "10^$x",
|
||||
# :log2 => x -> "2^$x",
|
||||
# :ln => x -> "e^$x",
|
||||
# )
|
||||
|
||||
const _label_func = Dict{Symbol,Function}(
|
||||
:log10 => x -> "10^$x",
|
||||
:log2 => x -> "2^$x",
|
||||
@@ -150,68 +141,41 @@ invscalefunc(scale::Symbol) = x -> get(_inv_scale_funcs, scale, identity)(Float6
|
||||
labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string)
|
||||
|
||||
function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
|
||||
amin,amax = axis_limits(axis)
|
||||
lims = axis_limits(axis)
|
||||
|
||||
# scale the limits
|
||||
scale = axis[:scale]
|
||||
sf = scalefunc(scale)
|
||||
|
||||
# If the axis input was a Date or DateTime use a special logic to find
|
||||
# "round" Date(Time)s as ticks
|
||||
# This bypasses the rest of optimal_ticks_and_labels, because
|
||||
# optimize_datetime_ticks returns ticks AND labels: the label format (Date
|
||||
# or DateTime) is chosen based on the time span between amin and amax
|
||||
# rather than on the input format
|
||||
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
|
||||
if ticks == nothing && scale == :identity
|
||||
if axis[:formatter] == dateformatter
|
||||
# optimize_datetime_ticks returns ticks and labels(!) based on
|
||||
# integers/floats corresponding to the DateTime type. Thus, the axes
|
||||
# limits, which resulted from converting the Date type to integers,
|
||||
# are converted to 'DateTime integers' (actually floats) before
|
||||
# being passed to optimize_datetime_ticks.
|
||||
# (convert(Int, convert(DateTime, convert(Date, i))) == 87600000*i)
|
||||
ticks, labels = optimize_datetime_ticks(864e5 * amin, 864e5 * amax;
|
||||
k_min = 2, k_max = 4)
|
||||
# Now the ticks are converted back to floats corresponding to Dates.
|
||||
return ticks / 864e5, labels
|
||||
elseif axis[:formatter] == datetimeformatter
|
||||
return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4)
|
||||
end
|
||||
end
|
||||
scaled_lims = map(scalefunc(scale), lims)
|
||||
# @show lims scaled_lims
|
||||
|
||||
# get a list of well-laid-out ticks
|
||||
scaled_ticks = if ticks == nothing
|
||||
optimize_ticks(
|
||||
sf(amin),
|
||||
sf(amax);
|
||||
cv = if ticks == nothing
|
||||
optimize_ticks(scaled_lims...,
|
||||
k_min = 5, # minimum number of ticks
|
||||
k_max = 8, # maximum number of ticks
|
||||
# span_buffer = 0.0 # padding buffer in case nice ticks are closeby
|
||||
)[1]
|
||||
else
|
||||
map(sf, filter(t -> amin <= t <= amax, ticks))
|
||||
ticks
|
||||
end
|
||||
unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
|
||||
|
||||
labels = if any(isfinite, unscaled_ticks)
|
||||
formatter = axis[:formatter]
|
||||
if formatter == :auto
|
||||
# the default behavior is to make strings of the scaled values and then apply the labelfunc
|
||||
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, :plain))
|
||||
elseif formatter == :scientific
|
||||
Showoff.showoff(unscaled_ticks, :scientific)
|
||||
else
|
||||
# there was an override for the formatter... use that on the unscaled ticks
|
||||
map(formatter, unscaled_ticks)
|
||||
end
|
||||
# # expand to ensure we see all the ticks
|
||||
# expand_extrema!(axis, cv)
|
||||
|
||||
# rescale and return values and labels
|
||||
# @show cv
|
||||
ticklabels = if any(isfinite, cv)
|
||||
map(labelfunc(scale, backend()), Showoff.showoff(cv, :plain))
|
||||
else
|
||||
# no finite ticks to show...
|
||||
String[]
|
||||
UTF8String[]
|
||||
end
|
||||
|
||||
# @show unscaled_ticks labels
|
||||
# labels = Showoff.showoff(unscaled_ticks, scale == :log10 ? :scientific : :auto)
|
||||
unscaled_ticks, labels
|
||||
tickvals = map(invscalefunc(scale), cv)
|
||||
# @show tickvals ticklabels
|
||||
# ticklabels = Showoff.showoff(tickvals, scale == :log10 ? :scientific : :auto)
|
||||
tickvals, ticklabels
|
||||
# basestr = scale == :log10 ? "10^" : scale == :log2 ? "2^" : scale == :ln ? "e^" : ""
|
||||
# tickvals, ["$basestr$cvi" for cvi in cv]
|
||||
end
|
||||
|
||||
# return (continuous_values, discrete_values) for the ticks on this axis
|
||||
@@ -229,7 +193,7 @@ function get_ticks(axis::Axis)
|
||||
elseif typeof(ticks) <: AVec
|
||||
# override ticks, but get the labels
|
||||
optimal_ticks_and_labels(axis, ticks)
|
||||
elseif typeof(ticks) <: NTuple{2, Any}
|
||||
elseif typeof(ticks) <: NTuple{2}
|
||||
# assuming we're passed (ticks, labels)
|
||||
ticks
|
||||
else
|
||||
@@ -238,7 +202,7 @@ function get_ticks(axis::Axis)
|
||||
# @show ticks dvals cv dv
|
||||
|
||||
# TODO: better/smarter cutoff values for sampling ticks
|
||||
if length(cv) > 30 && ticks == :auto
|
||||
if length(cv) > 30
|
||||
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)]
|
||||
cv[rng], dv[rng]
|
||||
else
|
||||
@@ -248,20 +212,9 @@ end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
function reset_extrema!(sp::Subplot)
|
||||
for asym in (:x,:y,:z)
|
||||
sp[Symbol(asym,:axis)][:extrema] = Extrema()
|
||||
end
|
||||
for series in sp.series_list
|
||||
expand_extrema!(sp, series.d)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function expand_extrema!(ex::Extrema, v::Number)
|
||||
ex.emin = NaNMath.min(v, ex.emin)
|
||||
ex.emax = NaNMath.max(v, ex.emax)
|
||||
ex.emin = min(v, ex.emin)
|
||||
ex.emax = max(v, ex.emax)
|
||||
ex
|
||||
end
|
||||
|
||||
@@ -276,8 +229,8 @@ expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
|
||||
|
||||
function expand_extrema!{MIN<:Number,MAX<:Number}(axis::Axis, v::Tuple{MIN,MAX})
|
||||
ex = axis[:extrema]
|
||||
ex.emin = NaNMath.min(v[1], ex.emin)
|
||||
ex.emax = NaNMath.max(v[2], ex.emax)
|
||||
ex.emin = min(v[1], ex.emin)
|
||||
ex.emax = max(v[2], ex.emax)
|
||||
ex
|
||||
end
|
||||
function expand_extrema!{N<:Number}(axis::Axis, v::AVec{N})
|
||||
@@ -290,22 +243,11 @@ end
|
||||
|
||||
|
||||
function expand_extrema!(sp::Subplot, d::KW)
|
||||
vert = isvertical(d)
|
||||
|
||||
# first expand for the data
|
||||
for letter in (:x, :y, :z)
|
||||
data = d[if vert
|
||||
letter
|
||||
else
|
||||
letter == :x ? :y : letter == :y ? :x : :z
|
||||
end]
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
|
||||
if isa(data, Volume)
|
||||
expand_extrema!(sp[:xaxis], data.x_extents)
|
||||
expand_extrema!(sp[:yaxis], data.y_extents)
|
||||
expand_extrema!(sp[:zaxis], data.z_extents)
|
||||
elseif eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf))
|
||||
data = d[letter]
|
||||
axis = sp.attr[Symbol(letter, "axis")]
|
||||
if 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 = d[letter] = Surface(Matrix{Float64}(data.surf))
|
||||
@@ -327,6 +269,7 @@ function expand_extrema!(sp::Subplot, d::KW)
|
||||
# end
|
||||
|
||||
# expand for fillrange
|
||||
vert = isvertical(d)
|
||||
fr = d[:fillrange]
|
||||
if fr == nothing && d[:seriestype] == :bar
|
||||
fr = 0.0
|
||||
@@ -349,11 +292,13 @@ function expand_extrema!(sp::Subplot, d::KW)
|
||||
|
||||
bw = d[:bar_width]
|
||||
if bw == nothing
|
||||
bw = d[:bar_width] = ignorenan_mean(diff(data))
|
||||
bw = d[:bar_width] = mean(diff(data))
|
||||
end
|
||||
# @show data bw
|
||||
|
||||
axis = sp.attr[Symbol(dsym, :axis)]
|
||||
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
|
||||
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
|
||||
expand_extrema!(axis, maximum(data) + 0.5maximum(bw))
|
||||
expand_extrema!(axis, minimum(data) - 0.5minimum(bw))
|
||||
end
|
||||
|
||||
end
|
||||
@@ -368,8 +313,8 @@ end
|
||||
# push the limits out slightly
|
||||
function widen(lmin, lmax)
|
||||
span = lmax - lmin
|
||||
# eps = NaNMath.max(1e-16, min(1e-2span, 1e-10))
|
||||
eps = NaNMath.max(1e-16, 0.03span)
|
||||
# eps = max(1e-16, min(1e-2span, 1e-10))
|
||||
eps = max(1e-16, 0.03span)
|
||||
lmin-eps, lmax+eps
|
||||
end
|
||||
|
||||
@@ -377,12 +322,10 @@ end
|
||||
# so lazy out and don't widen
|
||||
function default_should_widen(axis::Axis)
|
||||
should_widen = false
|
||||
if axis[:scale] == :identity && !is_2tuple(axis[:lims])
|
||||
for sp in axis.sps
|
||||
for series in series_list(sp)
|
||||
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
|
||||
should_widen = true
|
||||
end
|
||||
if axis[:scale] == :identity
|
||||
for series in series_list(axis.sp)
|
||||
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
|
||||
should_widen = true
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -405,9 +348,6 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
if amax <= amin && isfinite(amin)
|
||||
amax = amin + 1.0
|
||||
end
|
||||
if !isfinite(amin) && !isfinite(amax)
|
||||
amin, amax = 0.0, 1.0
|
||||
end
|
||||
if should_widen
|
||||
widen(amin, amax)
|
||||
else
|
||||
@@ -425,7 +365,7 @@ function discrete_value!(axis::Axis, dv)
|
||||
# @show axis[:discrete_map], axis[:discrete_values], dv
|
||||
if cv_idx == -1
|
||||
ex = axis[:extrema]
|
||||
cv = NaNMath.max(0.5, ex.emax + 1.0)
|
||||
cv = max(0.5, ex.emax + 1.0)
|
||||
expand_extrema!(axis, cv)
|
||||
push!(axis[:discrete_values], dv)
|
||||
push!(axis[:continuous_values], cv)
|
||||
@@ -500,11 +440,11 @@ function axis_drawing_info(sp::Subplot)
|
||||
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin)))
|
||||
|
||||
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
|
||||
# push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
|
||||
push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
|
||||
for xtick in xticks[1]
|
||||
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
|
||||
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid
|
||||
# push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
|
||||
push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
|
||||
end
|
||||
end
|
||||
|
||||
@@ -515,13 +455,14 @@ function axis_drawing_info(sp::Subplot)
|
||||
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
|
||||
|
||||
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
|
||||
# push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
|
||||
push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
|
||||
for ytick in yticks[1]
|
||||
push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick
|
||||
push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
|
||||
# push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
|
||||
push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
|
||||
end
|
||||
end
|
||||
|
||||
xticks, yticks, spine_segs, grid_segs
|
||||
end
|
||||
|
||||
|
||||
+40
-105
@@ -26,18 +26,24 @@ macro init_backend(s)
|
||||
end)
|
||||
end
|
||||
|
||||
@init_backend Immerse
|
||||
@init_backend Gadfly
|
||||
@init_backend PyPlot
|
||||
@init_backend Qwt
|
||||
@init_backend UnicodePlots
|
||||
@init_backend Winston
|
||||
@init_backend Bokeh
|
||||
@init_backend Plotly
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend GLVisualize
|
||||
@init_backend PGFPlots
|
||||
|
||||
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")
|
||||
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
|
||||
_prepare_plot_object(plt::Plot) = nothing
|
||||
@@ -51,46 +57,15 @@ _before_layout_calcs(plt::Plot) = nothing
|
||||
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt
|
||||
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt
|
||||
|
||||
"Returns the (width,height) of a text label."
|
||||
function text_size(lablen::Int, sz::Number, rot::Number = 0)
|
||||
# we need to compute the size of the ticks generically
|
||||
# this means computing the bounding box and then getting the width/height
|
||||
# note:
|
||||
ptsz = sz * pt
|
||||
width = 0.8lablen * ptsz
|
||||
|
||||
# now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||
height = abs(sind(rot)) * width + abs(cosd(rot)) * ptsz
|
||||
width = abs(sind(rot+90)) * width + abs(cosd(rot+90)) * ptsz
|
||||
width, height
|
||||
end
|
||||
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
|
||||
|
||||
# account for the size/length/rotation of tick labels
|
||||
# TODO: this should account for both tick font and the size/length/rotation of tick labels
|
||||
function tick_padding(axis::Axis)
|
||||
ticks = get_ticks(axis)
|
||||
if ticks == nothing
|
||||
ptsz = axis[:tickfont].pointsize * pt
|
||||
if axis[:ticks] in (nothing,false)
|
||||
0mm
|
||||
elseif axis[:letter] == :x
|
||||
2mm + ptsz
|
||||
else
|
||||
vals, labs = ticks
|
||||
isempty(labs) && return 0mm
|
||||
# ptsz = axis[:tickfont].pointsize * pt
|
||||
longest_label = maximum(length(lab) for lab in labs)
|
||||
|
||||
# generalize by "rotating" y labels
|
||||
rot = axis[:rotation] + (axis[:letter] == :y ? 90 : 0)
|
||||
|
||||
# # we need to compute the size of the ticks generically
|
||||
# # this means computing the bounding box and then getting the width/height
|
||||
# labelwidth = 0.8longest_label * ptsz
|
||||
#
|
||||
#
|
||||
# # now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||
# hgt = abs(sind(rot)) * labelwidth + abs(cosd(rot)) * ptsz + 1mm
|
||||
# hgt
|
||||
|
||||
# get the height of the rotated label
|
||||
text_size(longest_label, axis[:tickfont].pointsize, rot)[2]
|
||||
8mm
|
||||
end
|
||||
end
|
||||
|
||||
@@ -102,15 +77,6 @@ function _update_min_padding!(sp::Subplot)
|
||||
toppad = sp[:top_margin] + title_padding(sp)
|
||||
rightpad = sp[:right_margin]
|
||||
bottompad = tick_padding(sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
|
||||
|
||||
# switch them?
|
||||
if sp[:xaxis][:mirror]
|
||||
bottompad, toppad = toppad, bottompad
|
||||
end
|
||||
if sp[:yaxis][:mirror]
|
||||
leftpad, rightpad = rightpad, leftpad
|
||||
end
|
||||
|
||||
# @show (leftpad, toppad, rightpad, bottompad)
|
||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||
end
|
||||
@@ -148,7 +114,7 @@ function pickDefaultBackend()
|
||||
# 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")
|
||||
for pkgstr in ("PyPlot", "GR", "PlotlyJS", "Immerse", "Gadfly", "UnicodePlots")
|
||||
if Pkg.installed(pkgstr) != nothing
|
||||
return backend(Symbol(lowercase(pkgstr)))
|
||||
end
|
||||
@@ -174,15 +140,14 @@ function backend()
|
||||
sym = CURRENT_BACKEND.sym
|
||||
if !(sym in _initialized_backends)
|
||||
|
||||
# # initialize
|
||||
# println("[Plots.jl] Initializing backend: ", sym)
|
||||
# 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
|
||||
|
||||
@@ -199,14 +164,12 @@ function backend(pkg::AbstractBackend)
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
warn_on_deprecated_backend(CURRENT_BACKEND.sym)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
backend()
|
||||
end
|
||||
|
||||
function backend(modname::Symbol)
|
||||
warn_on_deprecated_backend(modname)
|
||||
CURRENT_BACKEND.sym = modname
|
||||
CURRENT_BACKEND.pkg = _backend_instance(modname)
|
||||
backend()
|
||||
end
|
||||
|
||||
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
|
||||
@@ -217,7 +180,23 @@ function warn_on_deprecated_backend(bsym::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
supported_types(::AbstractBackend) = []
|
||||
supported_styles(::AbstractBackend) = [:solid]
|
||||
supported_markers(::AbstractBackend) = [:none]
|
||||
supported_scales(::AbstractBackend) = [:identity]
|
||||
is_subplot_supported(::AbstractBackend) = false
|
||||
is_string_supported(::AbstractBackend) = false
|
||||
nativeImagesSupported(b::AbstractBackend) = :image in supported_types(b)
|
||||
|
||||
supported_types() = supported_types(backend())
|
||||
supported_styles() = supported_styles(backend())
|
||||
supported_markers() = supported_markers(backend())
|
||||
supported_scales() = supported_scales(backend())
|
||||
is_subplot_supported() = is_subplot_supported(backend())
|
||||
is_string_supported() = is_string_supported(backend())
|
||||
nativeImagesSupported() = nativeImagesSupported(backend())
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -247,7 +226,7 @@ const _base_supported_args = [
|
||||
:subplot_index,
|
||||
:discrete_values,
|
||||
:projection,
|
||||
|
||||
|
||||
]
|
||||
|
||||
function merge_with_base_supported(v::AVec)
|
||||
@@ -259,49 +238,5 @@ function merge_with_base_supported(v::AVec)
|
||||
end
|
||||
end
|
||||
end
|
||||
Set(v)
|
||||
v
|
||||
end
|
||||
|
||||
|
||||
|
||||
# @init_backend Immerse
|
||||
# @init_backend Gadfly
|
||||
@init_backend PyPlot
|
||||
# @init_backend Qwt
|
||||
@init_backend UnicodePlots
|
||||
# @init_backend Winston
|
||||
# @init_backend Bokeh
|
||||
@init_backend Plotly
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend GLVisualize
|
||||
@init_backend PGFPlots
|
||||
@init_backend InspectDR
|
||||
@init_backend HDF5
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# create the various `is_xxx_supported` and `supported_xxxs` methods
|
||||
# by default they pass through to checking membership in `_gr_xxx`
|
||||
for s in (:attr, :seriestype, :marker, :style, :scale)
|
||||
f = Symbol("is_", s, "_supported")
|
||||
f2 = Symbol("supported_", s, "s")
|
||||
@eval begin
|
||||
$f(::AbstractBackend, $s) = false
|
||||
$f(bend::AbstractBackend, $s::AbstractVector) = all(v -> $f(bend, v), $s)
|
||||
$f($s) = $f(backend(), $s)
|
||||
$f2() = $f2(backend())
|
||||
end
|
||||
|
||||
for bend in backends()
|
||||
bend_type = typeof(_backend_instance(bend))
|
||||
v = Symbol("_", bend, "_", s)
|
||||
@eval begin
|
||||
$f(::$bend_type, $s::Symbol) = $s in $v
|
||||
$f2(::$bend_type) = $v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# is_subplot_supported(::AbstractBackend) = false
|
||||
# is_subplot_supported() = is_subplot_supported(backend())
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
supported_attrs(::BokehBackend) = merge_with_base_supported([
|
||||
supported_args(::BokehBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
@@ -194,7 +194,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
|
||||
# TODO: write a png to io
|
||||
warn("mime png not implemented")
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
|
||||
supported_attrs(::GadflyBackend) = merge_with_base_supported([
|
||||
supported_args(::GadflyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
:group, :label, :seriestype,
|
||||
@@ -41,7 +41,7 @@ function _initialize_backend(::GadflyBackend; kw...)
|
||||
@eval begin
|
||||
import Gadfly, Compose
|
||||
export Gadfly, Compose
|
||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
||||
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -244,7 +244,7 @@ function addToGadflyLegend(plt::Plot, d::KW)
|
||||
|
||||
# add the legend if needed
|
||||
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
|
||||
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
|
||||
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", @compat(AbstractString)[], Color[]))
|
||||
end
|
||||
|
||||
# now add the series to the legend
|
||||
@@ -456,7 +456,7 @@ function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
|
||||
end
|
||||
|
||||
|
||||
function findGuideAndSet(gplt, t::DataType, args...; kw...)
|
||||
function findGuideAndSet(gplt, t::DataType, args...; kw...) #s::@compat(AbstractString))
|
||||
for (i,guide) in enumerate(gplt.guides)
|
||||
if isa(guide, t)
|
||||
gplt.guides[i] = t(args...; kw...)
|
||||
@@ -537,7 +537,7 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function createGadflyAnnotationObject(x, y, val::AbstractString)
|
||||
function createGadflyAnnotationObject(x, y, val::@compat(AbstractString))
|
||||
Gadfly.Guide.annotation(Compose.compose(
|
||||
Compose.context(),
|
||||
Compose.text(x, y, val)
|
||||
@@ -558,7 +558,7 @@ function createGadflyAnnotationObject(x, y, txt::PlotText)
|
||||
))
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
@@ -677,7 +677,7 @@ setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
function doshow{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P})
|
||||
function dowritemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P})
|
||||
gplt = getGadflyContext(plt)
|
||||
setGadflyDisplaySize(plt)
|
||||
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
|
||||
@@ -692,9 +692,9 @@ getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
|
||||
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
|
||||
|
||||
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
|
||||
@eval function Base.show{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P})
|
||||
@eval function Base.writemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P})
|
||||
func = getGadflyWriteFunc($mime())
|
||||
doshow(io, func, plt)
|
||||
dowritemime(io, func, plt)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -84,7 +84,7 @@ function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray,
|
||||
x = Compose.x_measure(xs[mod1(i, length(xs))])
|
||||
y = Compose.y_measure(ys[mod1(i, length(ys))])
|
||||
r = rs[mod1(i, length(rs))]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in cycle(geom.vertices, i)]
|
||||
end
|
||||
Gadfly.polygon(polys, geom.tag)
|
||||
end
|
||||
+266
-1417
File diff suppressed because it is too large
Load Diff
+128
-342
@@ -3,8 +3,7 @@
|
||||
|
||||
# significant contributions by @jheinen
|
||||
|
||||
|
||||
const _gr_attr = merge_with_base_supported([
|
||||
supported_args(::GRBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
@@ -20,7 +19,7 @@ const _gr_attr = merge_with_base_supported([
|
||||
:title, :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :legendtitle, :colorbar,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
@@ -30,25 +29,18 @@ const _gr_attr = merge_with_base_supported([
|
||||
:normalize, :weights,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
])
|
||||
const _gr_seriestype = [
|
||||
supported_types(::GRBackend) = [
|
||||
:path, :scatter,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :path3d, :scatter3d, :surface, :wireframe,
|
||||
:shape
|
||||
]
|
||||
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _gr_marker = _allMarkers
|
||||
const _gr_scale = [:identity, :log10]
|
||||
is_marker_supported(::GRBackend, shape::Shape) = true
|
||||
supported_styles(::GRBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::GRBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::GRBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::GRBackend) = true
|
||||
|
||||
function add_backend_string(::GRBackend)
|
||||
"""
|
||||
Pkg.add("GR")
|
||||
Pkg.build("GR")
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::GRBackend; kw...)
|
||||
@eval begin
|
||||
@@ -76,16 +68,12 @@ const gr_markertype = KW(
|
||||
:diamond => -13,
|
||||
:utriangle => -3,
|
||||
:dtriangle => -5,
|
||||
:ltriangle => -18,
|
||||
:rtriangle => -17,
|
||||
:pentagon => -21,
|
||||
:hexagon => -22,
|
||||
:heptagon => -23,
|
||||
:octagon => -24,
|
||||
:cross => 2,
|
||||
:xcross => 5,
|
||||
:+ => 2,
|
||||
:x => 5,
|
||||
:star4 => -25,
|
||||
:star5 => -26,
|
||||
:star6 => -27,
|
||||
@@ -124,17 +112,17 @@ function gr_getcolorind(c)
|
||||
convert(Int, GR.inqcolorfromrgb(red(c), green(c), blue(c)))
|
||||
end
|
||||
|
||||
gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(_cycle(c,1)))
|
||||
gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c,1)))
|
||||
gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(_cycle(c,1)))
|
||||
gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(_cycle(c,1)))
|
||||
gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(cycle(c,1)))
|
||||
gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(cycle(c,1)))
|
||||
gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(cycle(c,1)))
|
||||
gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(cycle(c,1)))
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# draw line segments, splitting x/y into contiguous/finite segments
|
||||
# note: this can be used for shapes by passing func `GR.fillarea`
|
||||
function gr_polyline(x, y, func = GR.polyline; arrowside=:none)
|
||||
function gr_polyline(x, y, func = GR.polyline)
|
||||
iend = 0
|
||||
n = length(x)
|
||||
while iend < n-1
|
||||
@@ -162,20 +150,12 @@ function gr_polyline(x, y, func = GR.polyline; arrowside=:none)
|
||||
# if we found a start and end, draw the line segment, otherwise we're done
|
||||
if istart > 0 && iend > 0
|
||||
func(x[istart:iend], y[istart:iend])
|
||||
if arrowside in (:head,:both)
|
||||
GR.drawarrow(x[iend-1], y[iend-1], x[iend], y[iend])
|
||||
end
|
||||
if arrowside in (:tail,:both)
|
||||
GR.drawarrow(x[istart+1], y[istart+1], x[istart], y[istart])
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
|
||||
|
||||
function gr_inqtext(x, y, s)
|
||||
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
|
||||
GR.inqtextext(x, y, s[2:end-1])
|
||||
@@ -186,8 +166,6 @@ function gr_inqtext(x, y, s)
|
||||
end
|
||||
end
|
||||
|
||||
gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
|
||||
|
||||
function gr_text(x, y, s)
|
||||
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
|
||||
GR.mathtex(x, y, s[2:end-1])
|
||||
@@ -219,14 +197,14 @@ function gr_polaraxes(rmin, rmax)
|
||||
GR.drawarc(-r, r, -r, r, 0, 359)
|
||||
end
|
||||
end
|
||||
for α in 0:45:315
|
||||
a = α + 90
|
||||
for alpha in 0:45:315
|
||||
a = alpha + 90
|
||||
sinf = sin(a * pi / 180)
|
||||
cosf = cos(a * pi / 180)
|
||||
GR.polyline([sinf, 0], [cosf, 0])
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
|
||||
x, y = GR.wctondc(1.1 * sinf, 1.1 * cosf)
|
||||
GR.textext(x, y, string(α, "^o"))
|
||||
GR.textext(x, y, string(alpha, "^o"))
|
||||
end
|
||||
GR.restorestate()
|
||||
end
|
||||
@@ -264,7 +242,7 @@ end
|
||||
|
||||
normalize_zvals(zv::Void) = zv
|
||||
function normalize_zvals(zv::AVec)
|
||||
vmin, vmax = ignorenan_extrema(zv)
|
||||
vmin, vmax = extrema(zv)
|
||||
if vmin == vmax
|
||||
zeros(length(zv))
|
||||
else
|
||||
@@ -272,56 +250,47 @@ function normalize_zvals(zv::AVec)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
gr_alpha(α::Void) = 1
|
||||
gr_alpha(α::Real) = α
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# draw ONE Shape
|
||||
function gr_draw_marker(xi, yi, msize, shape::Shape)
|
||||
sx, sy = coords(shape)
|
||||
# convert to ndc coords (percentages of window)
|
||||
sx, sy = shape_coords(shape)
|
||||
GR.selntran(0)
|
||||
w, h = gr_plot_size
|
||||
f = msize / (w + h)
|
||||
xi, yi = GR.wctondc(xi, yi)
|
||||
GR.fillarea(xi .+ sx .* f,
|
||||
yi .+ sy .* f)
|
||||
GR.fillarea(xi + sx * 0.0015msize,
|
||||
yi + sy * 0.0015msize)
|
||||
GR.selntran(1)
|
||||
end
|
||||
|
||||
# draw ONE symbol marker
|
||||
function gr_draw_marker(xi, yi, msize::Number, shape::Symbol)
|
||||
GR.setmarkertype(gr_markertype[shape])
|
||||
w, h = gr_plot_size
|
||||
GR.setmarkersize(0.3msize / ((w + h) * 0.001))
|
||||
GR.setmarkersize(0.3msize)
|
||||
GR.polymarker([xi], [yi])
|
||||
end
|
||||
|
||||
|
||||
# draw the markers, one at a time
|
||||
function gr_draw_markers(series::Series, x, y, msize, mz)
|
||||
shapes = series[:markershape]
|
||||
if shapes != :none
|
||||
shape = series[:markershape]
|
||||
if shape != :none
|
||||
for i=1:length(x)
|
||||
msi = _cycle(msize, i)
|
||||
shape = _cycle(shapes, i)
|
||||
msi = cycle(msize, i)
|
||||
cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor
|
||||
cfuncind = isa(shape, Shape) ? GR.setfillcolorind : GR.setmarkercolorind
|
||||
|
||||
# draw a filled in shape, slightly bigger, to estimate a stroke
|
||||
if series[:markerstrokewidth] > 0
|
||||
cfunc(_cycle(series[:markerstrokecolor], i)) #, series[:markerstrokealpha])
|
||||
cfunc(cycle(series[:markerstrokecolor], i)) #, series[:markerstrokealpha])
|
||||
gr_draw_marker(x[i], y[i], msi + series[:markerstrokewidth], shape)
|
||||
end
|
||||
|
||||
# draw the shape
|
||||
if mz == nothing
|
||||
cfunc(_cycle(series[:markercolor], i)) #, series[:markeralpha])
|
||||
cfunc(cycle(series[:markercolor], i)) #, series[:markeralpha])
|
||||
else
|
||||
# pick a color from the pre-loaded gradient
|
||||
ci = round(Int, 1000 + _cycle(mz, i) * 255)
|
||||
ci = round(Int, 1000 + cycle(mz, i) * 255)
|
||||
cfuncind(ci)
|
||||
GR.settransparency(_gr_gradient_alpha[ci-999])
|
||||
end
|
||||
@@ -342,10 +311,9 @@ end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function gr_set_line(lw, style, c) #, a)
|
||||
function gr_set_line(w, style, c) #, a)
|
||||
GR.setlinetype(gr_linetype[style])
|
||||
w, h = gr_plot_size
|
||||
GR.setlinewidth(max(0, lw / ((w + h) * 0.001)))
|
||||
GR.setlinewidth(w)
|
||||
gr_set_linecolor(c) #, a)
|
||||
end
|
||||
|
||||
@@ -357,14 +325,13 @@ function gr_set_fill(c) #, a)
|
||||
end
|
||||
|
||||
# this stores the conversion from a font pointsize to "percentage of window height" (which is what GR uses)
|
||||
const _gr_point_mult = 0.0018 * ones(1)
|
||||
const _gr_point_mult = zeros(1)
|
||||
|
||||
# set the font attributes... assumes _gr_point_mult has been populated already
|
||||
function gr_set_font(f::Font; halign = f.halign, valign = f.valign,
|
||||
color = f.color, rotation = f.rotation)
|
||||
function gr_set_font(f::Font; halign = f.halign, valign = f.valign, color = f.color)
|
||||
family = lowercase(f.family)
|
||||
GR.setcharheight(_gr_point_mult[1] * f.pointsize)
|
||||
GR.setcharup(sind(-rotation), cosd(-rotation))
|
||||
GR.setcharup(sin(f.rotation), cos(f.rotation))
|
||||
if haskey(gr_font_family, family)
|
||||
GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING)
|
||||
end
|
||||
@@ -372,14 +339,6 @@ function gr_set_font(f::Font; halign = f.halign, valign = f.valign,
|
||||
GR.settextalign(gr_halign[halign], gr_valign[valign])
|
||||
end
|
||||
|
||||
function gr_nans_to_infs!(z)
|
||||
for (i,zi) in enumerate(z)
|
||||
if zi == NaN
|
||||
z[i] = Inf
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
# viewport plot area
|
||||
|
||||
@@ -387,31 +346,20 @@ end
|
||||
# values are [xmin, xmax, ymin, ymax]. they range [0,1].
|
||||
const viewport_plotarea = zeros(4)
|
||||
|
||||
# the size of the current plot in pixels
|
||||
const gr_plot_size = [600.0, 400.0]
|
||||
|
||||
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
|
||||
function gr_viewport_from_bbox(bb::BoundingBox, w, h, viewport_canvas)
|
||||
viewport = zeros(4)
|
||||
viewport[1] = viewport_canvas[2] * (left(bb) / w)
|
||||
viewport[2] = viewport_canvas[2] * (right(bb) / w)
|
||||
viewport[3] = viewport_canvas[4] * (1.0 - bottom(bb) / h)
|
||||
viewport[4] = viewport_canvas[4] * (1.0 - top(bb) / h)
|
||||
if is3d(sp)
|
||||
vp = viewport[:]
|
||||
extent = min(vp[2] - vp[1], vp[4] - vp[3])
|
||||
viewport[1] = 0.5 * (vp[1] + vp[2] - extent)
|
||||
viewport[2] = 0.5 * (vp[1] + vp[2] + extent)
|
||||
viewport[3] = 0.5 * (vp[3] + vp[4] - extent)
|
||||
viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
|
||||
end
|
||||
viewport
|
||||
end
|
||||
|
||||
# change so we're focused on the viewport area
|
||||
function gr_set_viewport_cmap(sp::Subplot)
|
||||
GR.setviewport(
|
||||
viewport_plotarea[2] + (is3d(sp) ? 0.07 : 0.02),
|
||||
viewport_plotarea[2] + (is3d(sp) ? 0.10 : 0.05),
|
||||
viewport_plotarea[2] + (is3d(sp) ? 0.04 : 0.02),
|
||||
viewport_plotarea[2] + (is3d(sp) ? 0.07 : 0.05),
|
||||
viewport_plotarea[3],
|
||||
viewport_plotarea[4]
|
||||
)
|
||||
@@ -432,7 +380,7 @@ function gr_set_viewport_polar()
|
||||
ymax -= 0.05 * (xmax - xmin)
|
||||
xcenter = 0.5 * (xmin + xmax)
|
||||
ycenter = 0.5 * (ymin + ymax)
|
||||
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
|
||||
r = 0.5 * min(xmax - xmin, ymax - ymin)
|
||||
GR.setviewport(xcenter -r, xcenter + r, ycenter - r, ycenter + r)
|
||||
GR.setwindow(-1, 1, -1, 1)
|
||||
r
|
||||
@@ -442,41 +390,16 @@ end
|
||||
function gr_colorbar(sp::Subplot)
|
||||
if sp[:colorbar] != :none
|
||||
gr_set_viewport_cmap(sp)
|
||||
GR.colorbar()
|
||||
GR.colormap()
|
||||
gr_set_viewport_plotarea()
|
||||
end
|
||||
end
|
||||
|
||||
gr_view_xcenter() = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2])
|
||||
gr_view_ycenter() = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4])
|
||||
gr_view_xdiff() = viewport_plotarea[2] - viewport_plotarea[1]
|
||||
gr_view_ydiff() = viewport_plotarea[4] - viewport_plotarea[3]
|
||||
|
||||
function gr_legend_pos(s::Symbol,w,h)
|
||||
str = string(s)
|
||||
if str == "best"
|
||||
str = "topright"
|
||||
end
|
||||
if contains(str,"right")
|
||||
xpos = viewport_plotarea[2] - 0.05 - w
|
||||
elseif contains(str,"left")
|
||||
xpos = viewport_plotarea[1] + 0.11
|
||||
else
|
||||
xpos = (viewport_plotarea[2]-viewport_plotarea[1])/2 - w/2 +.04
|
||||
end
|
||||
if contains(str,"top")
|
||||
ypos = viewport_plotarea[4] - 0.06
|
||||
elseif contains(str,"bottom")
|
||||
ypos = viewport_plotarea[3] + h + 0.06
|
||||
else
|
||||
ypos = (viewport_plotarea[4]-viewport_plotarea[3])/2 + h/2
|
||||
end
|
||||
(xpos,ypos)
|
||||
end
|
||||
|
||||
function gr_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T},w,h)
|
||||
xpos = v[1] * (viewport_plotarea[2] - viewport_plotarea[1]) + viewport_plotarea[1]
|
||||
ypos = v[2] * (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_plotarea[3]
|
||||
(xpos,ypos)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -504,7 +427,6 @@ function gr_display(plt::Plot)
|
||||
# compute the viewport_canvas, normalized to the larger dimension
|
||||
viewport_canvas = Float64[0,1,0,1]
|
||||
w, h = plt[:size]
|
||||
gr_plot_size[:] = [w, h]
|
||||
if w > h
|
||||
ratio = float(h) / w
|
||||
msize = display_width_ratio * w
|
||||
@@ -537,66 +459,10 @@ function gr_display(plt::Plot)
|
||||
end
|
||||
|
||||
|
||||
function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
leftpad = 10mm
|
||||
toppad = 2mm
|
||||
rightpad = 2mm
|
||||
bottompad = 6mm
|
||||
if sp[:title] != ""
|
||||
toppad += 5mm
|
||||
end
|
||||
if sp[:xaxis][:guide] != ""
|
||||
xticks = axis_drawing_info(sp)[1]
|
||||
if !(xticks in (nothing, false))
|
||||
gr_set_font(sp[:xaxis][:tickfont],
|
||||
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
|
||||
valign = :top,
|
||||
color = sp[:xaxis][:foreground_color_axis],
|
||||
rotation = sp[:xaxis][:rotation])
|
||||
h = 0
|
||||
for (cv, dv) in zip(xticks...)
|
||||
tbx, tby = gr_inqtext(0, 0, string(dv))
|
||||
h = max(h, tby[2] - tby[1])
|
||||
end
|
||||
bottompad += 1mm + gr_plot_size[2] * h * px
|
||||
else
|
||||
bottompad += 4mm
|
||||
end
|
||||
end
|
||||
if sp[:yaxis][:guide] != ""
|
||||
leftpad += 4mm
|
||||
end
|
||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||
end
|
||||
|
||||
|
||||
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
# the viewports for this subplot
|
||||
viewport_subplot = gr_viewport_from_bbox(sp, bbox(sp), w, h, viewport_canvas)
|
||||
viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas)
|
||||
# get data limits
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
xy_lims = data_lims
|
||||
|
||||
ratio = sp[:aspect_ratio]
|
||||
if ratio != :none
|
||||
if ratio == :equal
|
||||
ratio = 1
|
||||
end
|
||||
viewport_ratio = (viewport_plotarea[2] - viewport_plotarea[1]) / (viewport_plotarea[4] - viewport_plotarea[3])
|
||||
window_ratio = (data_lims[2] - data_lims[1]) / (data_lims[4] - data_lims[3]) / ratio
|
||||
if window_ratio < viewport_ratio
|
||||
viewport_center = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2])
|
||||
viewport_size = (viewport_plotarea[2] - viewport_plotarea[1]) * window_ratio / viewport_ratio
|
||||
viewport_plotarea[1] = viewport_center - 0.5 * viewport_size
|
||||
viewport_plotarea[2] = viewport_center + 0.5 * viewport_size
|
||||
elseif window_ratio > viewport_ratio
|
||||
viewport_center = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4])
|
||||
viewport_size = (viewport_plotarea[4] - viewport_plotarea[3]) * viewport_ratio / window_ratio
|
||||
viewport_plotarea[3] = viewport_center - 0.5 * viewport_size
|
||||
viewport_plotarea[4] = viewport_center + 0.5 * viewport_size
|
||||
end
|
||||
end
|
||||
viewport_subplot = gr_viewport_from_bbox(bbox(sp), w, h, viewport_canvas)
|
||||
viewport_plotarea[:] = gr_viewport_from_bbox(plotarea(sp), w, h, viewport_canvas)
|
||||
|
||||
# fill in the plot area background
|
||||
bg = plot_color(sp[:background_color_inside])
|
||||
@@ -618,11 +484,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
if st == :heatmap
|
||||
outside_ticks = true
|
||||
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale])
|
||||
xy_lims = x[1], x[end], y[1], y[end]
|
||||
expand_extrema!(sp[:xaxis], x)
|
||||
expand_extrema!(sp[:yaxis], y)
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -639,18 +500,19 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
yaxis = sp[:yaxis]
|
||||
zaxis = sp[:zaxis]
|
||||
|
||||
# set the scale flags and window
|
||||
# get data limits and set the scale flags and window
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
xmin, xmax, ymin, ymax = data_lims
|
||||
scaleop = 0
|
||||
scale = 0
|
||||
xtick, ytick = 1, 1
|
||||
if xmax > xmin && ymax > ymin
|
||||
# NOTE: for log axes, the major_x and major_y - if non-zero (omit labels) - control the minor grid lines (1 = draw 9 minor grid lines, 2 = no minor grid lines)
|
||||
# NOTE: for log axes, the x_tick and y_tick - if non-zero (omit axes) - only affect the output appearance (1 = nomal, 2 = scientiic notation)
|
||||
xaxis[:scale] == :log10 && (scaleop |= GR.OPTION_X_LOG)
|
||||
yaxis[:scale] == :log10 && (scaleop |= GR.OPTION_Y_LOG)
|
||||
xaxis[:flip] && (scaleop |= GR.OPTION_FLIP_X)
|
||||
yaxis[:flip] && (scaleop |= GR.OPTION_FLIP_Y)
|
||||
if scaleop & GR.OPTION_X_LOG == 0
|
||||
xaxis[:scale] == :log10 && (scale |= GR.OPTION_X_LOG)
|
||||
yaxis[:scale] == :log10 && (scale |= GR.OPTION_Y_LOG)
|
||||
xaxis[:flip] && (scale |= GR.OPTION_FLIP_X)
|
||||
yaxis[:flip] && (scale |= GR.OPTION_FLIP_Y)
|
||||
if scale & GR.OPTION_X_LOG == 0
|
||||
majorx = 1 #5
|
||||
xtick = GR.tick(xmin, xmax) / majorx
|
||||
else
|
||||
@@ -658,7 +520,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
xtick = 2 # scientific notation
|
||||
majorx = 2 # no minor grid lines
|
||||
end
|
||||
if scaleop & GR.OPTION_Y_LOG == 0
|
||||
if scale & GR.OPTION_Y_LOG == 0
|
||||
majory = 1 #5
|
||||
ytick = GR.tick(ymin, ymax) / majory
|
||||
else
|
||||
@@ -669,7 +531,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
# NOTE: setwindow sets the "data coordinate" limits of the current "viewport"
|
||||
GR.setwindow(xmin, xmax, ymin, ymax)
|
||||
GR.setscale(scaleop)
|
||||
GR.setscale(scale)
|
||||
end
|
||||
|
||||
# draw the axes
|
||||
@@ -679,11 +541,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
if is3d(sp)
|
||||
zmin, zmax = gr_lims(zaxis, true)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (zmin = clims[1])
|
||||
isfinite(clims[2]) && (zmax = clims[2])
|
||||
end
|
||||
GR.setspace(zmin, zmax, 40, 70)
|
||||
xtick = GR.tick(xmin, xmax) / 2
|
||||
ytick = GR.tick(ymin, ymax) / 2
|
||||
@@ -692,16 +549,15 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
# GR.setlinetype(GR.LINETYPE_DOTTED)
|
||||
if sp[:grid]
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymax, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
|
||||
end
|
||||
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
|
||||
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
|
||||
|
||||
elseif ispolar(sp)
|
||||
r = gr_set_viewport_polar()
|
||||
rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
|
||||
# rmin, rmax = axis_limits(sp[:yaxis])
|
||||
rmin, rmax = GR.adjustrange(minimum(r), maximum(r))
|
||||
gr_polaraxes(rmin, rmax)
|
||||
|
||||
elseif draw_axes
|
||||
@@ -724,43 +580,42 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
# spine (border) and tick marks
|
||||
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(spine_segs)...)
|
||||
GR.setclip(1)
|
||||
|
||||
if !(xticks in (nothing, false))
|
||||
# x labels
|
||||
flip = sp[:yaxis][:flip]
|
||||
mirror = sp[:xaxis][:mirror]
|
||||
gr_set_font(sp[:xaxis][:tickfont],
|
||||
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
|
||||
valign = (mirror ? :bottom : :top),
|
||||
color = sp[:xaxis][:foreground_color_axis],
|
||||
rotation = sp[:xaxis][:rotation])
|
||||
gr_set_font(sp[:xaxis][:tickfont], valign = :top, color = sp[:xaxis][:foreground_color_axis])
|
||||
for (cv, dv) in zip(xticks...)
|
||||
# use xor ($) to get the right y coords
|
||||
xi, yi = GR.wctondc(cv, xor(flip, mirror) ? ymax : ymin)
|
||||
# @show cv dv ymin xi yi flip mirror (flip $ mirror)
|
||||
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3, string(dv))
|
||||
xi, yi = GR.wctondc(cv, flip ? ymax : ymin)
|
||||
# @show cv dv ymin xi yi
|
||||
gr_text(xi, yi-0.01, string(dv))
|
||||
end
|
||||
end
|
||||
|
||||
if !(yticks in (nothing, false))
|
||||
# y labels
|
||||
flip = sp[:xaxis][:flip]
|
||||
mirror = sp[:yaxis][:mirror]
|
||||
gr_set_font(sp[:yaxis][:tickfont],
|
||||
halign = (mirror ? :left : :right),
|
||||
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
|
||||
color = sp[:yaxis][:foreground_color_axis],
|
||||
rotation = sp[:yaxis][:rotation])
|
||||
gr_set_font(sp[:yaxis][:tickfont], halign = :right, color = sp[:yaxis][:foreground_color_axis])
|
||||
for (cv, dv) in zip(yticks...)
|
||||
# use xor ($) to get the right y coords
|
||||
xi, yi = GR.wctondc(xor(flip, mirror) ? xmax : xmin, cv)
|
||||
xi, yi = GR.wctondc(flip ? xmax : xmin, cv)
|
||||
# @show cv dv xmin xi yi
|
||||
gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv))
|
||||
gr_text(xi-0.01, yi, string(dv))
|
||||
end
|
||||
end
|
||||
|
||||
# window_diag = sqrt(gr_view_xdiff()^2 + gr_view_ydiff()^2)
|
||||
# ticksize = 0.0075 * window_diag
|
||||
# if outside_ticks
|
||||
# ticksize = -ticksize
|
||||
# end
|
||||
# # TODO: this should be done for each axis separately
|
||||
# gr_set_linecolor(xaxis[:foreground_color_axis])
|
||||
|
||||
# x1, x2 = xaxis[:flip] ? (xmax,xmin) : (xmin,xmax)
|
||||
# y1, y2 = yaxis[:flip] ? (ymax,ymin) : (ymin,ymax)
|
||||
# GR.axes(xtick, ytick, x1, y1, 1, 1, ticksize)
|
||||
# GR.axes(xtick, ytick, x2, y2, -1, -1, -ticksize)
|
||||
end
|
||||
# end
|
||||
|
||||
@@ -789,9 +644,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
GR.restorestate()
|
||||
|
||||
# TODO: can we remove?
|
||||
gr_set_font(xaxis[:tickfont])
|
||||
|
||||
# this needs to be here to point the colormap to the right indices
|
||||
GR.setcolormap(1000 + GR.COLORMAP_COOLWARM)
|
||||
|
||||
for (idx, series) in enumerate(series_list(sp))
|
||||
@@ -806,7 +660,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
GR.savestate()
|
||||
|
||||
|
||||
# update the bounding window
|
||||
if ispolar(sp)
|
||||
gr_set_viewport_polar()
|
||||
@@ -820,12 +673,17 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
x, y, z = series[:x], series[:y], series[:z]
|
||||
frng = series[:fillrange]
|
||||
|
||||
# add custom frame shapes to markershape?
|
||||
series_annotations_shapes!(series)
|
||||
# -------------------------------------------------------
|
||||
|
||||
# recompute data
|
||||
if typeof(z) <: Surface
|
||||
if st == :heatmap #&& size(z.surf) == (length(y), length(x))
|
||||
expand_extrema!(sp[:xaxis], (x[1]-0.5*(x[2]-x[1]), x[end]+0.5*(x[end]-x[end-1])))
|
||||
expand_extrema!(sp[:yaxis], (y[1]-0.5*(y[2]-y[1]), y[end]+0.5*(y[end]-y[end-1])))
|
||||
# # coords are centers... turn into edges
|
||||
# xd = diff(x)
|
||||
# x = vcat(x[1]-0.5xd[1], x[1]+xd, x[end]+0.5xd[end])
|
||||
# yd = diff(y)
|
||||
# y = vcat(y[1]-0.5yd[1], y[1]+yd, y[end]+0.5yd[end])
|
||||
end
|
||||
z = vec(transpose_z(series, z.surf, false))
|
||||
elseif ispolar(sp)
|
||||
if frng != nothing
|
||||
@@ -836,26 +694,27 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
if st in (:path, :scatter)
|
||||
if length(x) > 1
|
||||
|
||||
# do area fill
|
||||
if frng != nothing
|
||||
gr_set_fillcolor(series[:fillcolor]) #, series[:fillalpha])
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
|
||||
for (i,rng) in enumerate(iter_segments(series[:x], series[:y]))
|
||||
if length(rng) > 1
|
||||
gr_set_fillcolor(_cycle(series[:fillcolor], i))
|
||||
fx = _cycle(x, vcat(rng, reverse(rng)))
|
||||
fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
|
||||
# @show i rng fx fy
|
||||
GR.fillarea(fx, fy)
|
||||
end
|
||||
frng = isa(frng, Number) ? Float64[frng] : frng
|
||||
nx, ny, nf = length(x), length(y), length(frng)
|
||||
n = max(nx, ny)
|
||||
fx, fy = zeros(2n), zeros(2n)
|
||||
for i=1:n
|
||||
fx[i] = fx[end-i+1] = cycle(x,i)
|
||||
fy[i] = cycle(y,i)
|
||||
fy[end-i+1] = cycle(frng,i)
|
||||
end
|
||||
GR.fillarea(fx, fy)
|
||||
end
|
||||
|
||||
# draw the line(s)
|
||||
if st == :path
|
||||
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
|
||||
arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
|
||||
gr_polyline(x, y; arrowside = arrowside)
|
||||
gr_polyline(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -865,27 +724,22 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
elseif st == :contour
|
||||
zmin, zmax = gr_lims(zaxis, false)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (zmin = clims[1])
|
||||
isfinite(clims[2]) && (zmax = clims[2])
|
||||
end
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
if typeof(series[:levels]) <: Array
|
||||
h = series[:levels]
|
||||
else
|
||||
h = linspace(zmin, zmax, series[:levels])
|
||||
end
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
if series[:fillrange] != nothing
|
||||
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
|
||||
else
|
||||
GR.contour(x, y, h, z, 1000)
|
||||
end
|
||||
|
||||
|
||||
# create the colorbar of contour levels
|
||||
if sp[:colorbar] != :none
|
||||
gr_set_viewport_cmap(sp)
|
||||
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
|
||||
l = round(Int32, 1000 + (h - minimum(h)) / (maximum(h) - minimum(h)) * 255)
|
||||
GR.setwindow(xmin, xmax, zmin, zmax)
|
||||
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
|
||||
ztick = 0.5 * GR.tick(zmin, zmax)
|
||||
@@ -907,22 +761,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
cmap && gr_colorbar(sp)
|
||||
|
||||
elseif st == :heatmap
|
||||
xmin, xmax, ymin, ymax = xy_lims
|
||||
# z = vec(transpose_z(series, z.surf, false))
|
||||
zmin, zmax = gr_lims(zaxis, true)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (zmin = clims[1])
|
||||
isfinite(clims[2]) && (zmax = clims[2])
|
||||
end
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
|
||||
colors = [grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)] for zi=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) ), colors)
|
||||
w, h = length(x), length(y)
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||
# GR.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
||||
GR.surface(x, y, z, GR.OPTION_HEATMAP)
|
||||
cmap && gr_colorbar(sp)
|
||||
|
||||
elseif st in (:path3d, :scatter3d)
|
||||
@@ -945,7 +788,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.selntran(0)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
xmin, xmax, ymin, ymax = viewport_plotarea
|
||||
ymax -= 0.1 * (xmax - xmin)
|
||||
ymax -= 0.05 * (xmax - xmin)
|
||||
xcenter = 0.5 * (xmin + xmax)
|
||||
ycenter = 0.5 * (ymin + ymax)
|
||||
if xmax - xmin > ymax - ymin
|
||||
@@ -966,15 +809,15 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
a2 = round(Int, a1 + (slices[i] / total) * 360.0)
|
||||
GR.setfillcolorind(980 + (i-1) % 20)
|
||||
GR.fillarc(xmin, xmax, ymin, ymax, a1, a2)
|
||||
α = 0.5 * (a1 + a2)
|
||||
cosf = r * cos(α * pi / 180)
|
||||
sinf = r * sin(α * pi / 180)
|
||||
alpha = 0.5 * (a1 + a2)
|
||||
cosf = r * cos(alpha * pi / 180)
|
||||
sinf = r * sin(alpha * pi / 180)
|
||||
x[1] = xcenter + cosf
|
||||
y[1] = ycenter + sinf
|
||||
x[2] = x[1] + 0.1 * cosf
|
||||
y[2] = y[1] + 0.1 * sinf
|
||||
y[3] = y[2]
|
||||
if 90 <= α < 270
|
||||
if 90 <= alpha < 270
|
||||
x[3] = x[2] - 0.05
|
||||
GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF)
|
||||
gr_text(x[3] - 0.01, y[3], string(labels[i]))
|
||||
@@ -998,38 +841,31 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
x, y = series[:x][rng], series[:y][rng]
|
||||
|
||||
# draw the interior
|
||||
gr_set_fill(_cycle(series[:fillcolor], i))
|
||||
gr_set_fill(cycle(series[:fillcolor], i))
|
||||
GR.fillarea(x, y)
|
||||
|
||||
# draw the shapes
|
||||
gr_set_line(series[:linewidth], :solid, _cycle(series[:linecolor], i))
|
||||
gr_set_line(series[:linewidth], :solid, cycle(series[:linecolor], i))
|
||||
GR.polyline(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
elseif st == :image
|
||||
z = transpose_z(series, series[:z].surf, true)'
|
||||
w, h = size(z)
|
||||
if eltype(z) <: Colors.AbstractGray
|
||||
grey = round(UInt8, float(z) * 255)
|
||||
img = series[:z].surf
|
||||
w, h = size(img)
|
||||
if eltype(img) <: Colors.AbstractGray
|
||||
grey = round(UInt8, float(img) * 255)
|
||||
rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey)
|
||||
else
|
||||
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)
|
||||
round(Int, red(c) * 255) ), img)
|
||||
end
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||
end
|
||||
|
||||
# this is all we need to add the series_annotations text
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, x, y)
|
||||
gr_set_font(fnt)
|
||||
gr_text(GR.wctondc(xi, yi)..., str)
|
||||
end
|
||||
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
@@ -1043,11 +879,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
w = 0
|
||||
i = 0
|
||||
n = 0
|
||||
if sp[:legendtitle] != nothing
|
||||
tbx, tby = gr_inqtext(0, 0, string(sp[:legendtitle]))
|
||||
w = tbx[3] - tbx[1]
|
||||
n += 1
|
||||
end
|
||||
for series in series_list(sp)
|
||||
should_add_to_legend(series) || continue
|
||||
n += 1
|
||||
@@ -1061,9 +892,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
w = max(w, tbx[3] - tbx[1])
|
||||
end
|
||||
if w > 0
|
||||
xpos = viewport_plotarea[2] - 0.05 - w
|
||||
ypos = viewport_plotarea[4] - 0.06
|
||||
dy = _gr_point_mult[1] * sp[:legendfont].pointsize * 1.75
|
||||
h = dy*n
|
||||
(xpos,ypos) = gr_legend_pos(sp[:legend],w,h)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
gr_set_fillcolor(sp[:background_color_legend])
|
||||
GR.fillrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
|
||||
@@ -1071,41 +902,24 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.setlinewidth(1)
|
||||
GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
|
||||
i = 0
|
||||
if sp[:legendtitle] != nothing
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
|
||||
gr_set_textcolor(sp[:foreground_color_legend])
|
||||
GR.settransparency(1)
|
||||
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
|
||||
ypos -= dy
|
||||
end
|
||||
for series in series_list(sp)
|
||||
should_add_to_legend(series) || continue
|
||||
st = series[:seriestype]
|
||||
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
|
||||
|
||||
if st == :shape || series[:fillrange] != nothing
|
||||
if st == :path
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
|
||||
elseif st == :shape
|
||||
gr_set_fill(series[:fillcolor]) #, series[:fillalpha])
|
||||
l, r = xpos-0.07, xpos-0.01
|
||||
b, t = ypos-0.4dy, ypos+0.4dy
|
||||
x = [l, r, r, l, l]
|
||||
y = [b, b, t, t, b]
|
||||
GR.settransparency(gr_alpha(series[:fillalpha]))
|
||||
gr_polyline(x, y, GR.fillarea)
|
||||
GR.settransparency(gr_alpha(series[:linealpha]))
|
||||
st == :shape && gr_polyline(x, y)
|
||||
end
|
||||
|
||||
if st == :path
|
||||
GR.settransparency(gr_alpha(series[:linealpha]))
|
||||
if series[:fillrange] == nothing || series[:ribbon] != nothing
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
|
||||
else
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos+0.4dy, ypos+0.4dy])
|
||||
end
|
||||
gr_polyline(x, y)
|
||||
end
|
||||
|
||||
if series[:markershape] != :none
|
||||
gr_draw_markers(series, xpos - .035, ypos, 6, nothing)
|
||||
gr_draw_markers(series, xpos-[0.06,0.02], [ypos,ypos], 10, nothing)
|
||||
end
|
||||
|
||||
if typeof(series[:label]) <: Array
|
||||
@@ -1126,22 +940,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
# add annotations
|
||||
GR.savestate()
|
||||
# update the bounding window
|
||||
if ispolar(sp)
|
||||
gr_set_viewport_polar()
|
||||
else
|
||||
xmin, xmax, ymin, ymax = data_lims
|
||||
if xmax > xmin && ymax > ymin
|
||||
GR.setwindow(xmin, xmax, ymin, ymax)
|
||||
end
|
||||
end
|
||||
for ann in sp[:annotations]
|
||||
x, y, val = ann
|
||||
x, y = if is3d(sp)
|
||||
# GR.wc3towc(x, y, z)
|
||||
else
|
||||
GR.wctondc(x, y)
|
||||
end
|
||||
x, y = GR.wctondc(x, y)
|
||||
gr_set_font(val.font)
|
||||
gr_text(x, y, val.str)
|
||||
end
|
||||
@@ -1158,27 +959,18 @@ const _gr_mimeformats = Dict(
|
||||
"image/svg+xml" => "svg",
|
||||
)
|
||||
|
||||
const _gr_wstype_default = @static if is_linux()
|
||||
"x11"
|
||||
# "cairox11"
|
||||
elseif is_apple()
|
||||
"quartz"
|
||||
else
|
||||
"use_default"
|
||||
end
|
||||
|
||||
const _gr_wstype = Ref(get(ENV, "GKSwstype", _gr_wstype_default))
|
||||
gr_set_output(wstype::String) = (_gr_wstype[] = wstype)
|
||||
|
||||
for (mime, fmt) in _gr_mimeformats
|
||||
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend})
|
||||
@eval function _writemime(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend})
|
||||
GR.emergencyclosegks()
|
||||
wstype = haskey(ENV, "GKS_WSTYPE") ? ENV["GKS_WSTYPE"] : "0"
|
||||
filepath = tempname() * "." * $fmt
|
||||
ENV["GKSwstype"] = $fmt
|
||||
ENV["GKS_WSTYPE"] = $fmt
|
||||
ENV["GKS_FILEPATH"] = filepath
|
||||
gr_display(plt)
|
||||
GR.emergencyclosegks()
|
||||
write(io, readstring(filepath))
|
||||
write(io, readall(filepath))
|
||||
ENV["GKS_WSTYPE"] = wstype
|
||||
rm(filepath)
|
||||
end
|
||||
end
|
||||
@@ -1187,20 +979,14 @@ function _display(plt::Plot{GRBackend})
|
||||
if plt[:display_type] == :inline
|
||||
GR.emergencyclosegks()
|
||||
filepath = tempname() * ".pdf"
|
||||
ENV["GKSwstype"] = "pdf"
|
||||
ENV["GKS_WSTYPE"] = "pdf"
|
||||
ENV["GKS_FILEPATH"] = filepath
|
||||
gr_display(plt)
|
||||
GR.emergencyclosegks()
|
||||
content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(read, filepath)), "\a")
|
||||
content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(readbytes, filepath)), "\a")
|
||||
println(content)
|
||||
rm(filepath)
|
||||
else
|
||||
ENV["GKS_DOUBLE_BUF"] = true
|
||||
if _gr_wstype[] != "use_default"
|
||||
ENV["GKSwstype"] = _gr_wstype[]
|
||||
end
|
||||
gr_display(plt)
|
||||
end
|
||||
end
|
||||
|
||||
closeall(::GRBackend) = GR.emergencyclosegks()
|
||||
|
||||
@@ -1,655 +0,0 @@
|
||||
#HDF5 Plots: Save/replay plots to/from HDF5
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#==Usage
|
||||
===============================================================================
|
||||
Write to .hdf5 file using:
|
||||
p = plot(...)
|
||||
Plots.hdf5plot_write(p, "plotsave.hdf5")
|
||||
|
||||
Read from .hdf5 file using:
|
||||
pyplot() #Must first select backend
|
||||
pread = Plots.hdf5plot_read("plotsave.hdf5")
|
||||
display(pread)
|
||||
==#
|
||||
|
||||
|
||||
#==TODO
|
||||
===============================================================================
|
||||
1. Support more features
|
||||
- SeriesAnnotations & GridLayout known to be missing.
|
||||
3. Improve error handling.
|
||||
- Will likely crash if file format is off.
|
||||
2. Save data in a folder parallel to "plot".
|
||||
- Will make it easier for users to locate data.
|
||||
- Use HDF5 reference to link data?
|
||||
3. Develop an actual versioned file format.
|
||||
- Should have some form of backward compatibility.
|
||||
- Should be reliable for archival purposes.
|
||||
==#
|
||||
|
||||
|
||||
import FixedPointNumbers: N0f8 #In core Julia
|
||||
|
||||
#Dispatch types:
|
||||
immutable HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
|
||||
immutable HDF5CTuple; end #Identifies a "complex" tuple structure
|
||||
|
||||
type HDF5Plot_PlotRef
|
||||
ref::Union{Plot, Void}
|
||||
end
|
||||
|
||||
|
||||
#==Useful constants
|
||||
===============================================================================#
|
||||
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
|
||||
const _hdf5plot_countid = "COUNT" #Attribute for storing count
|
||||
|
||||
#Dict has problems using "Types" as keys. Initialize in "_initialize_backend":
|
||||
const HDF5PLOT_MAP_STR2TELEM = Dict{String, Type}()
|
||||
const HDF5PLOT_MAP_TELEM2STR = Dict{Type, String}()
|
||||
|
||||
#Don't really like this global variable... Very hacky
|
||||
const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
|
||||
|
||||
#Simple sub-structures that can just be written out using _hdf5plot_gwritefields:
|
||||
const HDF5PLOT_SIMPLESUBSTRUCT = Union{Font, BoundingBox,
|
||||
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText
|
||||
}
|
||||
|
||||
|
||||
#==
|
||||
===============================================================================#
|
||||
|
||||
const _hdf5_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
])
|
||||
const _hdf5_seriestype = [
|
||||
:path, :steppre, :steppost, :shape,
|
||||
:scatter, :hexbin, #:histogram2d, :histogram,
|
||||
# :bar,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _hdf5_marker = vcat(_allMarkers, :pixel)
|
||||
const _hdf5_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::HDF5Backend, shape::Shape) = true
|
||||
|
||||
function add_backend_string(::HDF5Backend)
|
||||
"""
|
||||
if !Plots.is_installed("HDF5")
|
||||
Pkg.add("HDF5")
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
#==Helper functions
|
||||
===============================================================================#
|
||||
|
||||
_hdf5_plotelempath(subpath::String) = "$_hdf5_plotroot/$subpath"
|
||||
_hdf5_datapath(subpath::String) = "$_hdf5_dataroot/$subpath"
|
||||
_hdf5_map_str2telem(k::String) = HDF5PLOT_MAP_STR2TELEM[k]
|
||||
_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].d, v.d)
|
||||
else
|
||||
dest[k] = v
|
||||
end
|
||||
end
|
||||
return
|
||||
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:
|
||||
const telem2str = Dict{String, Type}(
|
||||
"NATIVE" => HDF5PlotNative,
|
||||
"VOID" => Void,
|
||||
"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,
|
||||
"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})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# # this is called early in the pipeline, use it to make the plot current or something
|
||||
# function _prepare_plot_object(plt::Plot{HDF5Backend})
|
||||
# end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set up the subplot within the backend object.
|
||||
function _initialize_subplot(plt::Plot{HDF5Backend}, sp::Subplot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Add one series to the underlying backend object.
|
||||
# Called once per series
|
||||
# NOTE: Seems to be called when user calls plot()... even if backend
|
||||
# plot, sp.o has not yet been constructed...
|
||||
function _series_added(plt::Plot{HDF5Backend}, series::Series)
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# When series data is added/changed, this callback can do dynamic updates to the backend object.
|
||||
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
|
||||
function _series_updated(plt::Plot{HDF5Backend}, series::Series)
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
# for the calcs
|
||||
function _before_layout_calcs(plt::Plot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
function _update_plot_object(plt::Plot{HDF5Backend})
|
||||
#Do nothing
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
_show(io::IO, mime::MIME"text/plain", plt::Plot{HDF5Backend}) = nothing #Don't show
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Display/show the plot (open a GUI window, or browser page, for example).
|
||||
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)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
#==HDF5 write functions
|
||||
===============================================================================#
|
||||
|
||||
function _hdf5plot_writetype(grp, k::String, tstr::Array{String})
|
||||
d = HDF5.d_open(grp, k)
|
||||
HDF5.a_write(d, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_writetype(grp, k::String, T::Type)
|
||||
tstr = HDF5PLOT_MAP_TELEM2STR[T]
|
||||
d = HDF5.d_open(grp, k)
|
||||
HDF5.a_write(d, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_overwritetype(grp, k::String, T::Type)
|
||||
tstr = HDF5PLOT_MAP_TELEM2STR[T]
|
||||
d = HDF5.d_open(grp, k)
|
||||
HDF5.a_delete(d, _hdf5plot_datatypeid)
|
||||
HDF5.a_write(d, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_writetype(grp, T::Type) #Write directly to group
|
||||
tstr = HDF5PLOT_MAP_TELEM2STR[T]
|
||||
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_overwritetype(grp, T::Type) #Write directly to group
|
||||
tstr = HDF5PLOT_MAP_TELEM2STR[T]
|
||||
HDF5.a_delete(grp, _hdf5plot_datatypeid)
|
||||
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_writetype{T<:Any}(grp, ::Type{Array{T}})
|
||||
tstr = HDF5PLOT_MAP_TELEM2STR[Array] #ANY
|
||||
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_writetype{T<:BoundingBox}(grp, ::Type{T})
|
||||
tstr = HDF5PLOT_MAP_TELEM2STR[BoundingBox]
|
||||
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
|
||||
end
|
||||
function _hdf5plot_writecount(grp, n::Int) #Write directly to group
|
||||
HDF5.a_write(grp, _hdf5plot_countid, n)
|
||||
end
|
||||
function _hdf5plot_gwritefields(grp, k::String, v)
|
||||
grp = HDF5.g_create(grp, k)
|
||||
for _k in fieldnames(v)
|
||||
_v = getfield(v, _k)
|
||||
kstr = string(_k)
|
||||
_hdf5plot_gwrite(grp, kstr, _v)
|
||||
end
|
||||
_hdf5plot_writetype(grp, typeof(v))
|
||||
return
|
||||
end
|
||||
|
||||
# Write data
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _hdf5plot_gwrite(grp, k::String, v) #Default
|
||||
grp[k] = v
|
||||
_hdf5plot_writetype(grp, k, HDF5PlotNative)
|
||||
end
|
||||
function _hdf5plot_gwrite{T<:Number}(grp, k::String, v::Array{T}) #Default for arrays
|
||||
grp[k] = v
|
||||
_hdf5plot_writetype(grp, k, HDF5PlotNative)
|
||||
end
|
||||
#=
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Array{Any})
|
||||
# @show grp, k
|
||||
warn("Cannot write Array: $k=$v")
|
||||
end
|
||||
=#
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Void)
|
||||
grp[k] = 0
|
||||
_hdf5plot_writetype(grp, k, Void)
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Bool)
|
||||
grp[k] = Int(v)
|
||||
_hdf5plot_writetype(grp, k, Bool)
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Symbol)
|
||||
grp[k] = string(v)
|
||||
_hdf5plot_writetype(grp, k, Symbol)
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Tuple)
|
||||
varr = [v...]
|
||||
elt = eltype(varr)
|
||||
# if isleaftype(elt)
|
||||
|
||||
_hdf5plot_gwrite(grp, k, varr)
|
||||
if elt <: Number
|
||||
#We just wrote a simple dataset
|
||||
_hdf5plot_overwritetype(grp, k, Tuple)
|
||||
else #Used a more complex scheme (using subgroups):
|
||||
_hdf5plot_overwritetype(grp[k], HDF5CTuple)
|
||||
end
|
||||
#NOTE: _hdf5plot_overwritetype overwrites "Array" type with "Tuple".
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, d::Dict)
|
||||
# warn("Cannot write dict: $k=$d")
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Range)
|
||||
_hdf5plot_gwrite(grp, k, collect(v)) #For now
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::ARGB{N0f8})
|
||||
grp[k] = [v.r.i, v.g.i, v.b.i, v.alpha.i]
|
||||
_hdf5plot_writetype(grp, k, ARGB{N0f8})
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Colorant)
|
||||
_hdf5plot_gwrite(grp, k, ARGB{N0f8}(v))
|
||||
end
|
||||
#Custom vector (when not using simple numeric type):
|
||||
function _hdf5plot_gwritearray{T}(grp, k::String, v::Array{T})
|
||||
if "annotations" == k;
|
||||
return #Hack. Does not yet support annotations.
|
||||
end
|
||||
|
||||
vgrp = HDF5.g_create(grp, k)
|
||||
_hdf5plot_writetype(vgrp, Array) #ANY
|
||||
sz = size(v)
|
||||
|
||||
for iter in eachindex(v)
|
||||
coord = ind2sub(sz, iter)
|
||||
elem = v[iter]
|
||||
idxstr = join(coord, "_")
|
||||
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
|
||||
end
|
||||
|
||||
_hdf5plot_gwrite(vgrp, "dim", [sz...])
|
||||
return
|
||||
end
|
||||
_hdf5plot_gwrite(grp, k::String, v::Array) =
|
||||
_hdf5plot_gwritearray(grp, k, v)
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Extrema)
|
||||
grp[k] = [v.emin, v.emax]
|
||||
_hdf5plot_writetype(grp, k, Extrema)
|
||||
end
|
||||
function _hdf5plot_gwrite{T}(grp, k::String, v::Length{T})
|
||||
grp[k] = v.value
|
||||
_hdf5plot_writetype(grp, k, [HDF5PLOT_MAP_TELEM2STR[Length], string(T)])
|
||||
end
|
||||
|
||||
# Write more complex structures:
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Plot)
|
||||
#Don't write plot references
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::HDF5PLOT_SIMPLESUBSTRUCT)
|
||||
_hdf5plot_gwritefields(grp, k, v)
|
||||
return
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Axis)
|
||||
grp = HDF5.g_create(grp, k)
|
||||
for (_k, _v) in v.d
|
||||
kstr = string(_k)
|
||||
_hdf5plot_gwrite(grp, kstr, _v)
|
||||
end
|
||||
_hdf5plot_writetype(grp, Axis)
|
||||
return
|
||||
end
|
||||
#TODO: "Properly" support Nullable using _hdf5plot_writetype?
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Nullable)
|
||||
if isnull(v)
|
||||
_hdf5plot_gwrite(grp, k, nothing)
|
||||
else
|
||||
_hdf5plot_gwrite(grp, k, v.value)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
|
||||
#Currently no support for SeriesAnnotations
|
||||
return
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Subplot)
|
||||
grp = HDF5.g_create(grp, k)
|
||||
_hdf5plot_gwrite(grp, "index", v[:subplot_index])
|
||||
_hdf5plot_writetype(grp, Subplot)
|
||||
return
|
||||
end
|
||||
function _hdf5plot_write(grp, d::Dict)
|
||||
for (k, v) in d
|
||||
kstr = string(k)
|
||||
_hdf5plot_gwrite(grp, kstr, v)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# Write main plot structures:
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _hdf5plot_write(sp::Subplot{HDF5Backend}, subpath::String, f)
|
||||
f = f::HDF5.HDF5File #Assert
|
||||
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/attr"))
|
||||
_hdf5plot_write(grp, sp.attr)
|
||||
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/series_list"))
|
||||
_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.d)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function _hdf5plot_write(plt::Plot{HDF5Backend}, f)
|
||||
f = f::HDF5.HDF5File #Assert
|
||||
|
||||
grp = HDF5.g_create(f, _hdf5_plotelempath("attr"))
|
||||
_hdf5plot_write(grp, plt.attr)
|
||||
|
||||
grp = HDF5.g_create(f, _hdf5_plotelempath("subplots"))
|
||||
_hdf5plot_writecount(grp, length(plt.subplots))
|
||||
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
_hdf5plot_write(sp, "subplots/subplot$i", f)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
function hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString)
|
||||
HDF5.h5open(path, "w") do file
|
||||
_hdf5plot_write(plt, file)
|
||||
end
|
||||
end
|
||||
hdf5plot_write(path::AbstractString) = hdf5plot_write(current(), path)
|
||||
|
||||
|
||||
#==HDF5 playback (read) functions
|
||||
===============================================================================#
|
||||
|
||||
function _hdf5plot_readcount(grp) #Read directly from group
|
||||
return HDF5.a_read(grp, _hdf5plot_countid)
|
||||
end
|
||||
|
||||
_hdf5plot_convert(T::Type{HDF5PlotNative}, v) = v
|
||||
_hdf5plot_convert(T::Type{Void}, v) = nothing
|
||||
_hdf5plot_convert(T::Type{Bool}, v) = (v!=0)
|
||||
_hdf5plot_convert(T::Type{Symbol}, v) = Symbol(v)
|
||||
_hdf5plot_convert(T::Type{Tuple}, v) = tuple(v...) #With Vector{T<:Number}
|
||||
function _hdf5plot_convert(T::Type{ARGB{N0f8}}, v)
|
||||
r, g, b, a = reinterpret(N0f8, v)
|
||||
return Colors.ARGB{N0f8}(r, g, b, a)
|
||||
end
|
||||
_hdf5plot_convert(T::Type{Extrema}, v) = Extrema(v[1], v[2])
|
||||
|
||||
# Read data structures:
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _hdf5plot_read(grp, k::String, T::Type, dtid)
|
||||
v = HDF5.d_read(grp, k)
|
||||
return _hdf5plot_convert(T, v)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{Length}, dtid::Vector)
|
||||
v = HDF5.d_read(grp, k)
|
||||
TU = Symbol(dtid[2])
|
||||
T = typeof(v)
|
||||
return Length{TU,T}(v)
|
||||
end
|
||||
|
||||
# Read more complex data structures:
|
||||
# ----------------------------------------------------------------
|
||||
function _hdf5plot_read(grp, k::String, T::Type{Font}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
family = _hdf5plot_read(grp, "family")
|
||||
pointsize = _hdf5plot_read(grp, "pointsize")
|
||||
halign = _hdf5plot_read(grp, "halign")
|
||||
valign = _hdf5plot_read(grp, "valign")
|
||||
rotation = _hdf5plot_read(grp, "rotation")
|
||||
color = _hdf5plot_read(grp, "color")
|
||||
return Font(family, pointsize, halign, valign, rotation, color)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{Array}, dtid) #ANY
|
||||
grp = HDF5.g_open(grp, k)
|
||||
sz = _hdf5plot_read(grp, "dim")
|
||||
if [0] == sz; return []; end
|
||||
sz = tuple(sz...)
|
||||
result = Array{Any}(sz)
|
||||
|
||||
for iter in eachindex(result)
|
||||
coord = ind2sub(sz, iter)
|
||||
idxstr = join(coord, "_")
|
||||
result[iter] = _hdf5plot_read(grp, "v$idxstr")
|
||||
end
|
||||
|
||||
#Hack: Implicitly make Julia detect element type.
|
||||
# (Should probably write it explicitly to file)
|
||||
result = [result[iter] for iter in eachindex(result)] #Potentially make more specific
|
||||
return reshape(result, sz)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{HDF5CTuple}, dtid)
|
||||
v = _hdf5plot_read(grp, k, Array, dtid)
|
||||
return tuple(v...)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{ColorGradient}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
colors = _hdf5plot_read(grp, "colors")
|
||||
values = _hdf5plot_read(grp, "values")
|
||||
return ColorGradient(colors, values)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{BoundingBox}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
x0 = _hdf5plot_read(grp, "x0")
|
||||
a = _hdf5plot_read(grp, "a")
|
||||
return BoundingBox(x0, a)
|
||||
end
|
||||
_hdf5plot_read(grp, k::String, T::Type{RootLayout}, dtid) = RootLayout()
|
||||
function _hdf5plot_read(grp, k::String, T::Type{GridLayout}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
# parent = _hdf5plot_read(grp, "parent")
|
||||
parent = RootLayout()
|
||||
minpad = _hdf5plot_read(grp, "minpad")
|
||||
bbox = _hdf5plot_read(grp, "bbox")
|
||||
grid = _hdf5plot_read(grp, "grid")
|
||||
widths = _hdf5plot_read(grp, "widths")
|
||||
heights = _hdf5plot_read(grp, "heights")
|
||||
attr = KW() #TODO support attr: _hdf5plot_read(grp, "attr")
|
||||
|
||||
return GridLayout(parent, minpad, bbox, grid, widths, heights, attr)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{Axis}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
kwlist = KW()
|
||||
_hdf5plot_read(grp, kwlist)
|
||||
return Axis([], kwlist)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{Subplot}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
idx = _hdf5plot_read(grp, "index")
|
||||
return HDF5PLOT_PLOTREF.ref.subplots[idx]
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String)
|
||||
dtid = HDF5.a_read(grp[k], _hdf5plot_datatypeid)
|
||||
T = _hdf5_map_str2telem(dtid) #expect exception
|
||||
return _hdf5plot_read(grp, k, T, dtid)
|
||||
end
|
||||
|
||||
#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)
|
||||
d[Symbol(k)] = v
|
||||
catch e
|
||||
@show e
|
||||
@show grp
|
||||
warn("Could not read field $k")
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# Read main plot structures:
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _hdf5plot_read(sp::Subplot, subpath::String, f)
|
||||
f = f::HDF5.HDF5File #Assert
|
||||
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
|
||||
kwlist = KW()
|
||||
_hdf5plot_read(grp, kwlist)
|
||||
_hdf5_merge!(sp.attr, kwlist)
|
||||
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list"))
|
||||
nseries = _hdf5plot_readcount(grp)
|
||||
|
||||
for i in 1:nseries
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list/series$i"))
|
||||
kwlist = KW()
|
||||
_hdf5plot_read(grp, kwlist)
|
||||
plot!(sp, kwlist[:x], kwlist[:y]) #Add data & create data structures
|
||||
_hdf5_merge!(sp.series_list[end].d, kwlist)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function _hdf5plot_read(plt::Plot, f)
|
||||
f = f::HDF5.HDF5File #Assert
|
||||
#Assumpltion: subplots are already allocated (plt.subplots)
|
||||
|
||||
HDF5PLOT_PLOTREF.ref = plt #Used when reading "layout"
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("attr"))
|
||||
_hdf5plot_read(grp, plt.attr)
|
||||
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
_hdf5plot_read(sp, "subplots/subplot$i", f)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function hdf5plot_read(path::AbstractString)
|
||||
plt = nothing
|
||||
HDF5.h5open(path, "r") do file
|
||||
grp = HDF5.g_open(file, _hdf5_plotelempath("subplots"))
|
||||
n = _hdf5plot_readcount(grp)
|
||||
plt = plot(layout=n) #Get reference to a new plot
|
||||
_hdf5plot_read(plt, file)
|
||||
end
|
||||
return plt
|
||||
end
|
||||
|
||||
#Last line
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
supported_attrs(::ImmerseBackend) = supported_attrs(GadflyBackend())
|
||||
supported_args(::ImmerseBackend) = supported_args(GadflyBackend())
|
||||
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
|
||||
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
|
||||
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
|
||||
@@ -14,7 +14,7 @@ function _initialize_backend(::ImmerseBackend; kw...)
|
||||
@eval begin
|
||||
import Immerse, Gadfly, Compose, Gtk
|
||||
export Immerse, Gadfly, Compose, Gtk
|
||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
||||
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -61,7 +61,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
@@ -1,528 +0,0 @@
|
||||
|
||||
# https://github.com/ma-laforge/InspectDR.jl
|
||||
|
||||
#=TODO:
|
||||
Tweak scale factor for width & other sizes
|
||||
|
||||
Not supported by InspectDR:
|
||||
:foreground_color_grid
|
||||
:foreground_color_border
|
||||
:polar,
|
||||
|
||||
Add in functionality to Plots.jl:
|
||||
:aspect_ratio,
|
||||
=#
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
#TODO: remove features
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokestyle, #Causes warning not to have it... what is this?
|
||||
:fillcolor, :fillalpha, #:fillrange,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :scale, #:ticks, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, #:colorbar,
|
||||
# :marker_z,
|
||||
# :line_z,
|
||||
# :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
:dpi,
|
||||
# :colorbar_title,
|
||||
])
|
||||
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _inspectdr_seriestype = [
|
||||
:path, :scatter, :shape #, :steppre, :steppost
|
||||
]
|
||||
#see: _allMarkers, _shape_keys
|
||||
const _inspectdr_marker = Symbol[
|
||||
:none, :auto,
|
||||
:circle, :rect, :diamond,
|
||||
:cross, :xcross,
|
||||
:utriangle, :dtriangle, :rtriangle, :ltriangle,
|
||||
:pentagon, :hexagon, :heptagon, :octagon,
|
||||
:star4, :star5, :star6, :star7, :star8,
|
||||
:vline, :hline, :+, :x,
|
||||
]
|
||||
|
||||
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
is_marker_supported(::InspectDRBackend, shape::Shape) = true
|
||||
|
||||
_inspectdr_to_pixels(bb::BoundingBox) =
|
||||
InspectDR.BoundingBox(to_pixels(left(bb)), to_pixels(right(bb)), to_pixels(top(bb)), to_pixels(bottom(bb)))
|
||||
|
||||
#Do we avoid Map to avoid possible pre-comile issues?
|
||||
function _inspectdr_mapglyph(s::Symbol)
|
||||
s == :rect && return :square
|
||||
return s
|
||||
end
|
||||
|
||||
function _inspectdr_mapglyph(s::Shape)
|
||||
x, y = coords(s)
|
||||
return InspectDR.GlyphPolyline(x, y)
|
||||
end
|
||||
|
||||
# py_marker(markers::AVec) = map(py_marker, markers)
|
||||
function _inspectdr_mapglyph(markers::AVec)
|
||||
warn("Vectors of markers are currently unsupported in InspectDR.")
|
||||
_inspectdr_mapglyph(markers[1])
|
||||
end
|
||||
|
||||
_inspectdr_mapglyphsize(v::Real) = v
|
||||
function _inspectdr_mapglyphsize(v::Vector)
|
||||
warn("Vectors of marker sizes are currently unsupported in InspectDR.")
|
||||
_inspectdr_mapglyphsize(v[1])
|
||||
end
|
||||
|
||||
_inspectdr_mapcolor(v::Colorant) = v
|
||||
function _inspectdr_mapcolor(g::PlotUtils.ColorGradient)
|
||||
warn("Color gradients are currently unsupported in InspectDR.")
|
||||
#Pick middle color:
|
||||
_inspectdr_mapcolor(g.colors[div(1+end,2)])
|
||||
end
|
||||
function _inspectdr_mapcolor(v::AVec)
|
||||
warn("Vectors of colors are currently unsupported in InspectDR.")
|
||||
#Pick middle color:
|
||||
_inspectdr_mapcolor(v[div(1+end,2)])
|
||||
end
|
||||
|
||||
#Hack: suggested point size does not seem adequate relative to plot size, for some reason.
|
||||
_inspectdr_mapptsize(v) = 1.5*v
|
||||
|
||||
function _inspectdr_add_annotations(plot, x, y, val)
|
||||
#What kind of annotation is this?
|
||||
end
|
||||
|
||||
#plot::InspectDR.Plot2D
|
||||
function _inspectdr_add_annotations(plot, x, y, val::PlotText)
|
||||
vmap = Dict{Symbol, Symbol}(:top=>:t, :bottom=>:b) #:vcenter
|
||||
hmap = Dict{Symbol, Symbol}(:left=>:l, :right=>:r) #:hcenter
|
||||
align = Symbol(get(vmap, val.font.valign, :c), get(hmap, val.font.halign, :c))
|
||||
fnt = InspectDR.Font(val.font.family, val.font.pointsize,
|
||||
color =_inspectdr_mapcolor(val.font.color)
|
||||
)
|
||||
ann = InspectDR.atext(val.str, x=x, y=y,
|
||||
font=fnt, angle=val.font.rotation, align=align
|
||||
)
|
||||
InspectDR.add(plot, ann)
|
||||
return
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_getscale(s::Symbol, yaxis::Bool)
|
||||
#TODO: Support :asinh, :sqrt
|
||||
kwargs = yaxis? (:tgtmajor=>8, :tgtminor=>2): () #More grid lines on y-axis
|
||||
if :log2 == s
|
||||
return InspectDR.AxisScale(:log2; kwargs...)
|
||||
elseif :log10 == s
|
||||
return InspectDR.AxisScale(:log10; kwargs...)
|
||||
elseif :ln == s
|
||||
return InspectDR.AxisScale(:ln; kwargs...)
|
||||
else #identity
|
||||
return InspectDR.AxisScale(:lin; kwargs...)
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::InspectDRBackend)
|
||||
"""
|
||||
if !Plots.is_installed("InspectDR")
|
||||
Pkg.add("InspectDR")
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::InspectDRBackend; kw...)
|
||||
@eval begin
|
||||
import InspectDR
|
||||
export InspectDR
|
||||
|
||||
#Glyph used when plotting "Shape"s:
|
||||
const INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
|
||||
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
|
||||
)
|
||||
|
||||
type InspecDRPlotRef
|
||||
mplot::Union{Void, InspectDR.Multiplot}
|
||||
gui::Union{Void, 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
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Create the window/figure for this backend.
|
||||
function _create_backend_figure(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
#:overwrite_figure: want to reuse current figure
|
||||
if plt[:overwrite_figure] && mplot != nothing
|
||||
mplot.subplots = [] #Reset
|
||||
if gplot != nothing #Ensure still references current plot
|
||||
gplot.src = mplot
|
||||
end
|
||||
else #want new one:
|
||||
mplot = InspectDR.Multiplot()
|
||||
gplot = nothing #Will be created later
|
||||
end
|
||||
|
||||
#break link with old subplots
|
||||
for sp in plt.subplots
|
||||
sp.o = nothing
|
||||
end
|
||||
|
||||
return InspecDRPlotRef(mplot, gplot)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# # this is called early in the pipeline, use it to make the plot current or something
|
||||
# function _prepare_plot_object(plt::Plot{InspectDRBackend})
|
||||
# end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set up the subplot within the backend object.
|
||||
function _initialize_subplot(plt::Plot{InspectDRBackend}, sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
#Don't do anything without a "subplot" object: Will process later.
|
||||
if nothing == plot; return; end
|
||||
plot.data = []
|
||||
plot.userannot = [] #Clear old markers/text annotation/polyline "annotation"
|
||||
return plot
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Add one series to the underlying backend object.
|
||||
# Called once per series
|
||||
# NOTE: Seems to be called when user calls plot()... even if backend
|
||||
# plot, sp.o has not yet been constructed...
|
||||
function _series_added(plt::Plot{InspectDRBackend}, series::Series)
|
||||
st = series[:seriestype]
|
||||
sp = series[:subplot]
|
||||
plot = sp.o
|
||||
|
||||
#Don't do anything without a "subplot" object: Will process later.
|
||||
if nothing == plot; return; end
|
||||
|
||||
_vectorize(v) = isa(v, Vector)? v: collect(v) #InspectDR only supports vectors
|
||||
x = _vectorize(series[:x]); y = _vectorize(series[:y])
|
||||
|
||||
#No support for polar grid... but can still perform polar transformation:
|
||||
if ispolar(sp)
|
||||
Θ = x; r = y
|
||||
x = r.*cos(Θ); y = r.*sin(Θ)
|
||||
end
|
||||
|
||||
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
|
||||
nx = length(x); ny = length(y)
|
||||
if nx < ny
|
||||
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
elseif ny > nx
|
||||
series[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
end
|
||||
|
||||
#= TODO: Eventually support
|
||||
series[:fillcolor] #I think this is fill under line
|
||||
zorder = series[:series_plotindex]
|
||||
|
||||
For st in :shape:
|
||||
zorder = series[:series_plotindex],
|
||||
=#
|
||||
|
||||
if st in (:shape,)
|
||||
nmax = 0
|
||||
for (i,rng) in enumerate(iter_segments(x, y))
|
||||
nmax = i
|
||||
if length(rng) > 1
|
||||
linewidth = series[:linewidth]
|
||||
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
|
||||
line = InspectDR.line(
|
||||
style=:solid, width=linewidth, color=linecolor
|
||||
)
|
||||
apline = InspectDR.PolylineAnnotation(
|
||||
x[rng], y[rng], line=line, fillcolor=fillcolor
|
||||
)
|
||||
InspectDR.add(plot, apline)
|
||||
end
|
||||
end
|
||||
|
||||
i = (nmax >= 2? div(nmax, 2): nmax) #Must pick one set of colors for legend
|
||||
if i > 1 #Add dummy waveform for legend entry:
|
||||
linewidth = series[:linewidth]
|
||||
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
|
||||
wfrm = InspectDR.add(plot, Float64[], Float64[], id=series[:label])
|
||||
wfrm.line = InspectDR.line(
|
||||
style=:none, width=linewidth, #linewidth affects glyph
|
||||
)
|
||||
wfrm.glyph = InspectDR.glyph(
|
||||
shape = INSPECTDR_GLYPH_SHAPE, size = 8,
|
||||
color = linecolor, fillcolor = fillcolor
|
||||
)
|
||||
end
|
||||
elseif st in (:path, :scatter) #, :steppre, :steppost)
|
||||
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
|
||||
linewidth = series[:linewidth]
|
||||
#More efficient & allows some support for markerstrokewidth:
|
||||
_style = (0==linewidth? :none: series[:linestyle])
|
||||
wfrm = InspectDR.add(plot, x, y, id=series[:label])
|
||||
wfrm.line = InspectDR.line(
|
||||
style = _style,
|
||||
width = series[:linewidth],
|
||||
color = series[:linecolor],
|
||||
)
|
||||
#InspectDR does not control markerstrokewidth independently.
|
||||
if :none == _style
|
||||
#Use this property only if no line is displayed:
|
||||
wfrm.line.width = series[:markerstrokewidth]
|
||||
end
|
||||
wfrm.glyph = InspectDR.glyph(
|
||||
shape = _inspectdr_mapglyph(series[:markershape]),
|
||||
size = _inspectdr_mapglyphsize(series[:markersize]),
|
||||
color = _inspectdr_mapcolor(series[:markerstrokecolor]),
|
||||
fillcolor = _inspectdr_mapcolor(series[:markercolor]),
|
||||
)
|
||||
end
|
||||
|
||||
# this is all we need to add the series_annotations text
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, x, y)
|
||||
_inspectdr_add_annotations(plot, xi, yi, PlotText(str, fnt))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# When series data is added/changed, this callback can do dynamic updates to the backend object.
|
||||
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
|
||||
function _series_updated(plt::Plot{InspectDRBackend}, series::Series)
|
||||
#Nothing to do
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
const gridon = InspectDR.GridRect(vmajor=true, hmajor=true)
|
||||
const gridoff = InspectDR.GridRect()
|
||||
const plot = sp.o
|
||||
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
|
||||
|
||||
#No independent control of grid???
|
||||
strip.grid = sp[:grid]? gridon: gridoff
|
||||
|
||||
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
|
||||
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
|
||||
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
|
||||
xmin, xmax = axis_limits(xaxis)
|
||||
ymin, ymax = axis_limits(yaxis)
|
||||
if ispolar(sp)
|
||||
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
|
||||
rmax = NaNMath.max(abs(ymin), abs(ymax))
|
||||
xmin, xmax = -rmax, rmax
|
||||
ymin, ymax = -rmax, rmax
|
||||
end
|
||||
plot.xext = InspectDR.PExtents1D() #reset
|
||||
strip.yext = InspectDR.PExtents1D() #reset
|
||||
plot.xext_full = InspectDR.PExtents1D(xmin, xmax)
|
||||
strip.yext_full = InspectDR.PExtents1D(ymin, ymax)
|
||||
a = plot.annotation
|
||||
a.title = sp[:title]
|
||||
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
|
||||
|
||||
l = plot.layout
|
||||
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l[:font_title] = InspectDR.Font(sp[:titlefont].family,
|
||||
_inspectdr_mapptsize(sp[:titlefont].pointsize),
|
||||
color = _inspectdr_mapcolor(sp[:foreground_color_title])
|
||||
)
|
||||
#Cannot independently control fonts of axes with InspectDR:
|
||||
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefont].family,
|
||||
_inspectdr_mapptsize(xaxis[:guidefont].pointsize),
|
||||
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide])
|
||||
)
|
||||
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfont].family,
|
||||
_inspectdr_mapptsize(xaxis[:tickfont].pointsize),
|
||||
color = _inspectdr_mapcolor(xaxis[:foreground_color_text])
|
||||
)
|
||||
l[:enable_legend] = (sp[:legend] != :none)
|
||||
#l[:halloc_legend] = 150 #TODO: compute???
|
||||
l[:font_legend] = InspectDR.Font(sp[:legendfont].family,
|
||||
_inspectdr_mapptsize(sp[:legendfont].pointsize),
|
||||
color = _inspectdr_mapcolor(sp[:foreground_color_legend])
|
||||
)
|
||||
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
end
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
# for the calcs
|
||||
function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
const mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
|
||||
mplot.title = plt[:plot_title]
|
||||
if "" == mplot.title
|
||||
#Don't use window_title... probably not what you want.
|
||||
#mplot.title = plt[:window_title]
|
||||
end
|
||||
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
|
||||
|
||||
resize!(mplot.subplots, length(plt.subplots))
|
||||
nsubplots = length(plt.subplots)
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
if !isassigned(mplot.subplots, i)
|
||||
mplot.subplots[i] = InspectDR.Plot2D()
|
||||
end
|
||||
sp.o = mplot.subplots[i]
|
||||
plot = sp.o
|
||||
_initialize_subplot(plt, sp)
|
||||
_inspectdr_setupsubplot(sp)
|
||||
|
||||
# add the annotations
|
||||
for ann in sp[:annotations]
|
||||
_inspectdr_add_annotations(plot, ann...)
|
||||
end
|
||||
end
|
||||
|
||||
#Do not yet support absolute plot positionning.
|
||||
#Just try to make things look more-or less ok:
|
||||
if nsubplots <= 1
|
||||
mplot.layout[:ncolumns] = 1
|
||||
elseif nsubplots <= 4
|
||||
mplot.layout[:ncolumns] = 2
|
||||
elseif nsubplots <= 6
|
||||
mplot.layout[:ncolumns] = 3
|
||||
elseif nsubplots <= 12
|
||||
mplot.layout[:ncolumns] = 4
|
||||
else
|
||||
mplot.layout[:ncolumns] = 5
|
||||
end
|
||||
|
||||
for series in plt.series_list
|
||||
_series_added(plt, series)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Set the (left, top, right, bottom) minimum padding around the plot area
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
|
||||
#Computing plotbounds with 0-BoundingBox returns required padding:
|
||||
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
|
||||
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
|
||||
#TODO: possibly zero-out items not in use??
|
||||
|
||||
# add in the user-specified margin to InspectDR padding:
|
||||
leftpad = abs(bb.xmin)*px + sp[:left_margin]
|
||||
toppad = abs(bb.ymin)*px + sp[:top_margin]
|
||||
rightpad = abs(bb.xmax)*px + sp[:right_margin]
|
||||
bottompad = abs(bb.ymax)*px + sp[:bottom_margin]
|
||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# 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
|
||||
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
graphbb = _inspectdr_to_pixels(plotarea(sp))
|
||||
plot = mplot.subplots[i]
|
||||
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
|
||||
end
|
||||
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
if nothing == gplot; return; end
|
||||
|
||||
gplot.src = mplot #Ensure still references current plot
|
||||
InspectDR.refresh(gplot)
|
||||
return
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _inspectdr_mimeformats_dpi = Dict(
|
||||
"image/png" => "png"
|
||||
)
|
||||
const _inspectdr_mimeformats_nodpi = Dict(
|
||||
"image/svg+xml" => "svg",
|
||||
"application/eps" => "eps",
|
||||
"image/eps" => "eps",
|
||||
# "application/postscript" => "ps", #TODO: support once Cairo supports PSSurface
|
||||
"application/pdf" => "pdf"
|
||||
)
|
||||
_inspectdr_show(io::IO, mime::MIME, ::Void, w, h) =
|
||||
throw(ErrorException("Cannot show(::IO, ...) plot - not yet generated"))
|
||||
function _inspectdr_show(io::IO, mime::MIME, mplot, w, h)
|
||||
InspectDR._show(io, mime, mplot, Float64(w), Float64(h))
|
||||
end
|
||||
|
||||
for (mime, fmt) in _inspectdr_mimeformats_dpi
|
||||
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{InspectDRBackend})
|
||||
dpi = plt[:dpi]#TODO: support
|
||||
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
|
||||
end
|
||||
end
|
||||
for (mime, fmt) in _inspectdr_mimeformats_nodpi
|
||||
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{InspectDRBackend})
|
||||
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
|
||||
end
|
||||
end
|
||||
_show(io::IO, mime::MIME"text/plain", plt::Plot{InspectDRBackend}) = nothing #Don't show
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# Display/show the plot (open a GUI window, or browser page, for example).
|
||||
function _display(plt::Plot{InspectDRBackend})
|
||||
mplot = _inspectdr_getmplot(plt.o)
|
||||
if nothing == mplot; return; end
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
if nothing == gplot
|
||||
gplot = display(InspectDR.GtkDisplay(), mplot)
|
||||
else
|
||||
#redundant... Plots.jl will call _update_plot_object:
|
||||
#InspectDR.refresh(gplot)
|
||||
end
|
||||
plt.o = InspecDRPlotRef(mplot, gplot)
|
||||
return gplot
|
||||
end
|
||||
+32
-136
@@ -2,8 +2,8 @@
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
const _pgfplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
supported_args(::PGFPlotsBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
@@ -22,30 +22,25 @@ const _pgfplots_attr = merge_with_base_supported([
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
:colorbar,
|
||||
:marker_z, #:levels,
|
||||
# :colorbar,
|
||||
# :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :polar,
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
supported_types(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
|
||||
supported_styles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::PGFPlotsBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
|
||||
supported_scales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10]
|
||||
is_subplot_supported(::PGFPlotsBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::PGFPlotsBackend)
|
||||
"""
|
||||
Pkg.add("PGFPlots")
|
||||
Pkg.build("PGFPlots")
|
||||
"""
|
||||
end
|
||||
|
||||
function _initialize_backend(::PGFPlotsBackend; kw...)
|
||||
@eval begin
|
||||
@@ -69,8 +64,6 @@ const _pgfplots_markers = KW(
|
||||
:none => "none",
|
||||
:cross => "+",
|
||||
:xcross => "x",
|
||||
:+ => "+",
|
||||
:x => "x",
|
||||
:utriangle => "triangle*",
|
||||
:dtriangle => "triangle*",
|
||||
:circle => "*",
|
||||
@@ -98,35 +91,14 @@ const _pgf_series_extrastyle = KW(
|
||||
:xsticks => "xcomb",
|
||||
)
|
||||
|
||||
# PGFPlots uses the anchors to define orientations for example to align left
|
||||
# one needs to use the right edge as anchor
|
||||
const _pgf_annotation_halign = KW(
|
||||
:center => "",
|
||||
:left => "right",
|
||||
:right => "left"
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
# takes in color,alpha, and returns color and alpha appropriate for pgf style
|
||||
function pgf_color(c::Colorant)
|
||||
function pgf_color(c)
|
||||
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", red(c), green(c), blue(c))
|
||||
cstr, alpha(c)
|
||||
end
|
||||
|
||||
function pgf_color(grad::ColorGradient)
|
||||
# Can't handle ColorGradient here, fallback to defaults.
|
||||
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316,0.97868012)
|
||||
cstr, 1
|
||||
end
|
||||
|
||||
# Generates a colormap for pgfplots based on a ColorGradient
|
||||
function pgf_colormap(grad::ColorGradient)
|
||||
join(map(grad.colors) do c
|
||||
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
|
||||
end,", ")
|
||||
end
|
||||
|
||||
function pgf_fillstyle(d::KW)
|
||||
cstr,a = pgf_color(d[:fillcolor])
|
||||
"fill = $cstr, fill opacity=$a"
|
||||
@@ -157,19 +129,6 @@ function pgf_marker(d::KW)
|
||||
}"""
|
||||
end
|
||||
|
||||
function pgf_add_annotation!(o,x,y,val)
|
||||
# Construct the style string.
|
||||
# Currently supports color and orientation
|
||||
cstr,a = pgf_color(val.font.color)
|
||||
push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text
|
||||
x, y,
|
||||
style="""
|
||||
$(get(_pgf_annotation_halign,val.font.halign,"")),
|
||||
color=$cstr, draw opacity=$(convert(Float16,a)),
|
||||
rotate=$(val.font.rotation)
|
||||
"""))
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function pgf_series(sp::Subplot, series::Series)
|
||||
@@ -177,18 +136,17 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
st = d[:seriestype]
|
||||
style = []
|
||||
kw = KW()
|
||||
|
||||
push!(style, pgf_linestyle(d))
|
||||
push!(style, pgf_marker(d))
|
||||
|
||||
if d[:fillrange] != nothing || st in (:shape,)
|
||||
if d[:fillrange] != nothing
|
||||
push!(style, pgf_fillstyle(d))
|
||||
end
|
||||
|
||||
# add to legend?
|
||||
if sp[:legend] != :none && should_add_to_legend(series)
|
||||
kw[:legendentry] = d[:label]
|
||||
else
|
||||
push!(style, "forget plot")
|
||||
end
|
||||
|
||||
# function args
|
||||
@@ -196,10 +154,6 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
d[:z].surf, d[:x], d[:y]
|
||||
elseif is3d(st)
|
||||
d[:x], d[:y], d[:z]
|
||||
elseif d[:marker_z] != nothing
|
||||
# If a marker_z is used pass it as third coordinate to a 2D plot.
|
||||
# See "Scatter Plots" in PGFPlots documentation
|
||||
d[:x], d[:y], d[:marker_z]
|
||||
else
|
||||
d[:x], d[:y]
|
||||
end
|
||||
@@ -248,9 +202,6 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# axis guide
|
||||
kw[Symbol(letter,:label)] = axis[:guide]
|
||||
|
||||
# Add ticklabel rotations
|
||||
push!(style, "$(letter)ticklabel style={rotate = $(axis[:rotation])}")
|
||||
|
||||
# flip/reverse?
|
||||
axis[:flip] && push!(style, "$letter dir=reverse")
|
||||
|
||||
@@ -274,12 +225,6 @@ function pgf_axis(sp::Subplot, letter)
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :auto))
|
||||
ticks = get_ticks(axis)
|
||||
push!(style, string(letter, "tick = {", join(ticks[1],","), "}"))
|
||||
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}"))
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
style, kw
|
||||
end
|
||||
@@ -287,14 +232,10 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
function _make_pgf_plot!(plt::Plot)
|
||||
plt.o = PGFPlots.Axis[]
|
||||
# Obtain the total height of the plot by extracting the maximal bottom
|
||||
# coordinate from the bounding box.
|
||||
total_height = bottom(bbox(plt.layout))
|
||||
|
||||
for sp in plt.subplots
|
||||
# first build the PGFPlots.Axis object
|
||||
# first build the PGFPlots.Axis object
|
||||
style = ["unbounded coords=jump"]
|
||||
kw = KW()
|
||||
|
||||
@@ -302,26 +243,26 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
for letter in (:x, :y, :z)
|
||||
if letter != :z || is3d(sp)
|
||||
axisstyle, axiskw = pgf_axis(sp, letter)
|
||||
append!(style, axisstyle)
|
||||
merge!(kw, axiskw)
|
||||
for sty in axisstyle
|
||||
push!(style, sty)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# bounding box values are in mm
|
||||
# note: bb origin is top-left, pgf is bottom-left
|
||||
# A round on 2 decimal places should be enough precision for 300 dpi
|
||||
# plots.
|
||||
bb = bbox(sp)
|
||||
push!(style, """
|
||||
xshift = $(left(bb).value)mm,
|
||||
yshift = $(round((total_height - (bottom(bb))).value,2))mm,
|
||||
yshift = $((height(bb) - (bottom(bb))).value)mm,
|
||||
width = $(width(bb).value)mm,
|
||||
height = $(height(bb).value)mm,
|
||||
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
|
||||
""")
|
||||
kw[:width] = "$(width(bb).value)mm"
|
||||
kw[:height] = "$(height(bb).value)mm"
|
||||
|
||||
if sp[:title] != ""
|
||||
kw[:title] = "$(sp[:title])"
|
||||
push!(style, "title = $(sp[:title])")
|
||||
end
|
||||
|
||||
sp[:grid] && push!(style, "grid = major")
|
||||
@@ -334,67 +275,27 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
kw[:legendPos] = _pgfplots_legend_pos[legpos]
|
||||
end
|
||||
|
||||
axisf = PGFPlots.Axis
|
||||
if sp[:projection] == :polar
|
||||
axisf = PGFPlots.PolarAxis
|
||||
end
|
||||
|
||||
# Search series for any gradient. In case one series uses a gradient set
|
||||
# the colorbar and colomap.
|
||||
# The reasoning behind doing this on the axis level is that pgfplots
|
||||
# colorbar seems to only works on axis level and needs the proper colormap for
|
||||
# correctly displaying it.
|
||||
# It's also possible to assign the colormap to the series itself but
|
||||
# then the colormap needs to be added twice, once for the axis and once for the
|
||||
# series.
|
||||
# As it is likely that all series within the same axis use the same
|
||||
# colormap this should not cause any problem.
|
||||
for series in series_list(sp)
|
||||
for col in (:markercolor, :fillcolor)
|
||||
if typeof(series.d[col]) == ColorGradient
|
||||
push!(style,"colormap={plots}{$(pgf_colormap(series.d[col]))}")
|
||||
|
||||
if sp[:colorbar] == :none
|
||||
kw[:colorbar] = "false"
|
||||
else
|
||||
kw[:colorbar] = "true"
|
||||
end
|
||||
# goto is needed to break out of col and series for
|
||||
@goto colorbar_end
|
||||
end
|
||||
end
|
||||
end
|
||||
@label colorbar_end
|
||||
|
||||
o = axisf(; style = style, kw...)
|
||||
o = PGFPlots.Axis(; style = style, kw...)
|
||||
|
||||
# add the series object to the PGFPlots.Axis
|
||||
for series in series_list(sp)
|
||||
push!(o, pgf_series(sp, series))
|
||||
|
||||
# add series annotations
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
|
||||
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt))
|
||||
end
|
||||
end
|
||||
|
||||
# add the annotations
|
||||
for ann in sp[:annotations]
|
||||
pgf_add_annotation!(o,ann...)
|
||||
end
|
||||
|
||||
|
||||
# add the PGFPlots.Axis to the list
|
||||
push!(plt.o, o)
|
||||
end
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
|
||||
show(io, mime, plt.o)
|
||||
|
||||
function _writemime(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
function _writemime(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
|
||||
# prepare the object
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
@@ -403,20 +304,15 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
|
||||
|
||||
# read it into io
|
||||
write(io, readstring(open(fn)))
|
||||
write(io, readall(open(fn)))
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
|
||||
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
|
||||
fn = tempname()*".tex"
|
||||
PGFPlots.save(fn, backend_object(plt), include_preamble=false)
|
||||
write(io, readstring(open(fn)))
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PGFPlotsBackend})
|
||||
# prepare the object
|
||||
_make_pgf_plot!(plt)
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save an svg
|
||||
|
||||
+44
-181
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
const _plotly_attr = merge_with_base_supported([
|
||||
supported_args(::PlotlyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
@@ -19,52 +19,41 @@ const _plotly_attr = merge_with_base_supported([
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar, :colorbar_title,
|
||||
:marker_z, :fill_z, :levels,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
# :contours,
|
||||
:aspect_ratio,
|
||||
# :contours, :aspect_ratio,
|
||||
:hover,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:clims,
|
||||
])
|
||||
|
||||
const _plotly_seriestype = [
|
||||
supported_types(::PlotlyBackend) = [
|
||||
:path, :scatter, :bar, :pie, :heatmap,
|
||||
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
|
||||
:contour, :surface, :path3d, :scatter3d, :shape, :scattergl,
|
||||
]
|
||||
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _plotly_marker = [
|
||||
supported_styles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::PlotlyBackend) = [
|
||||
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
|
||||
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
|
||||
]
|
||||
const _plotly_scale = [:identity, :log10]
|
||||
supported_scales(::PlotlyBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::PlotlyBackend) = true
|
||||
# is_string_supported(::PlotlyBackend) = true
|
||||
is_string_supported(::PlotlyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
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"
|
||||
|
||||
function _initialize_backend(::PlotlyBackend; kw...)
|
||||
@eval begin
|
||||
import JSON
|
||||
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
|
||||
|
||||
_js_code = open(readstring, _plotly_js_path, "r")
|
||||
_js_path = Pkg.dir("Plots", "deps", "plotly-latest.min.js")
|
||||
_js_code = open(@compat(readstring), _js_path, "r")
|
||||
|
||||
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
|
||||
_js_script = """
|
||||
@@ -95,20 +84,6 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _plotly_legend_pos = KW(
|
||||
:right => [1., 0.5],
|
||||
:left => [0., 0.5],
|
||||
:top => [0.5, 1.],
|
||||
:bottom => [0.5, 0.],
|
||||
:bottomleft => [0., 0.],
|
||||
:bottomright => [1., 0.],
|
||||
:topright => [1., 1.],
|
||||
:topleft => [0., 1.]
|
||||
)
|
||||
|
||||
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
|
||||
plotly_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T}) = v
|
||||
|
||||
function plotly_font(font::Font, color = font.color)
|
||||
KW(
|
||||
:family => font.family,
|
||||
@@ -117,7 +92,6 @@ function plotly_font(font::Font, color = font.color)
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
|
||||
KW(
|
||||
:text => val,
|
||||
@@ -134,7 +108,7 @@ function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper"
|
||||
:font => plotly_font(ptxt.font),
|
||||
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
|
||||
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
|
||||
:rotation => -ptxt.font.rotation,
|
||||
:rotation => ptxt.font.rotation,
|
||||
))
|
||||
end
|
||||
|
||||
@@ -169,41 +143,11 @@ function plotly_scale(scale::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
function shrink_by(lo, sz, ratio)
|
||||
amt = 0.5 * (1.0 - ratio) * sz
|
||||
lo + amt, sz - 2amt
|
||||
end
|
||||
|
||||
function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
|
||||
aspect_ratio = sp[:aspect_ratio]
|
||||
if aspect_ratio != :none
|
||||
if aspect_ratio == :equal
|
||||
aspect_ratio = 1.0
|
||||
end
|
||||
xmin,xmax = axis_limits(sp[:xaxis])
|
||||
ymin,ymax = axis_limits(sp[:yaxis])
|
||||
want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio
|
||||
parea_ratio = width(plotarea) / height(plotarea)
|
||||
if want_ratio > parea_ratio
|
||||
# need to shrink y
|
||||
ratio = parea_ratio / want_ratio
|
||||
pcts[2], pcts[4] = shrink_by(pcts[2], pcts[4], ratio)
|
||||
elseif want_ratio < parea_ratio
|
||||
# need to shrink x
|
||||
ratio = want_ratio / parea_ratio
|
||||
pcts[1], pcts[3] = shrink_by(pcts[1], pcts[3], ratio)
|
||||
end
|
||||
pcts
|
||||
end
|
||||
pcts
|
||||
end
|
||||
|
||||
|
||||
# this method gets the start/end in percentage of the canvas for this axis direction
|
||||
function plotly_domain(sp::Subplot, letter)
|
||||
figw, figh = sp.plt[:size]
|
||||
pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px)
|
||||
pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts)
|
||||
i1,i2 = (letter == :x ? (1,3) : (2,4))
|
||||
[pcts[i1], pcts[i1]+pcts[i2]]
|
||||
end
|
||||
@@ -215,7 +159,6 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
:title => axis[:guide],
|
||||
:showgrid => sp[:grid],
|
||||
:zeroline => false,
|
||||
:ticks => "inside",
|
||||
)
|
||||
|
||||
if letter in (:x,:y)
|
||||
@@ -223,7 +166,10 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))"
|
||||
end
|
||||
|
||||
ax[:tickangle] = -axis[:rotation]
|
||||
rot = axis[:rotation]
|
||||
if rot != 0
|
||||
ax[:tickangle] = rot
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, :none))
|
||||
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
|
||||
@@ -235,7 +181,7 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
# lims
|
||||
lims = axis[:lims]
|
||||
if lims != :auto && limsType(lims) == :limits
|
||||
ax[:range] = map(scalefunc(axis[:scale]), lims)
|
||||
ax[:range] = lims
|
||||
end
|
||||
|
||||
# flip
|
||||
@@ -269,14 +215,13 @@ function plotly_layout(plt::Plot)
|
||||
w, h = plt[:size]
|
||||
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)
|
||||
d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>20)
|
||||
|
||||
d_out[:annotations] = KW[]
|
||||
|
||||
for sp in plt.subplots
|
||||
spidx = plotly_subplot_index(sp)
|
||||
|
||||
|
||||
# add an annotation for the title... positioned horizontally relative to plotarea,
|
||||
# but vertically just below the top of the subplot bounding box
|
||||
if sp[:title] != ""
|
||||
@@ -296,6 +241,8 @@ function plotly_layout(plt::Plot)
|
||||
|
||||
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
|
||||
|
||||
# TODO: x/y axis tick values/labels
|
||||
|
||||
# if any(is3d, seriesargs)
|
||||
if is3d(sp)
|
||||
d_out[:scene] = KW(
|
||||
@@ -310,32 +257,17 @@ function plotly_layout(plt::Plot)
|
||||
|
||||
# legend
|
||||
d_out[:showlegend] = sp[:legend] != :none
|
||||
xpos,ypos = plotly_legend_pos(sp[:legend])
|
||||
if sp[:legend] != :none
|
||||
d_out[:legend] = KW(
|
||||
:bgcolor => rgba_string(sp[:background_color_legend]),
|
||||
:bordercolor => rgba_string(sp[:foreground_color_legend]),
|
||||
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]),
|
||||
:x => xpos,
|
||||
:y => ypos
|
||||
)
|
||||
end
|
||||
|
||||
# annotations
|
||||
append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]])
|
||||
|
||||
# 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!(d_out[:annotations], plotly_annotation_dict(
|
||||
xi,
|
||||
yi,
|
||||
PlotText(str,fnt); xref = "x$spidx", yref = "y$spidx")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# # arrows
|
||||
# for sargs in seriesargs
|
||||
# a = sargs[:arrow]
|
||||
@@ -372,11 +304,9 @@ end
|
||||
plotly_colorscale(c, α) = plotly_colorscale(cgrad(alpha=α), α)
|
||||
# plotly_colorscale(c, alpha = nothing) = plotly_colorscale(cgrad(), alpha)
|
||||
|
||||
|
||||
const _plotly_markers = KW(
|
||||
:rect => "square",
|
||||
:xcross => "x",
|
||||
:x => "x",
|
||||
:utriangle => "triangle-up",
|
||||
:dtriangle => "triangle-down",
|
||||
:star5 => "star-triangle-up",
|
||||
@@ -396,23 +326,14 @@ function plotly_close_shapes(x, y)
|
||||
xs, ys = nansplit(x), nansplit(y)
|
||||
for i=1:length(xs)
|
||||
shape = Shape(xs[i], ys[i])
|
||||
xs[i], ys[i] = coords(shape)
|
||||
xs[i], ys[i] = shape_coords(shape)
|
||||
end
|
||||
nanvcat(xs), nanvcat(ys)
|
||||
end
|
||||
|
||||
plotly_data(v) = collect(v)
|
||||
plotly_data(surf::Surface) = surf.surf
|
||||
plotly_data{R<:Rational}(v::AbstractArray{R}) = float(v)
|
||||
|
||||
plotly_surface_data(series::Series, a::AbstractVector) = a
|
||||
plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false)
|
||||
plotly_surface_data(series::Series, a::Surface) = plotly_surface_data(series, a.surf)
|
||||
|
||||
#ensures that a gradient is called if a single color is supplied where a gradient is needed (e.g. if a series recipe defines marker_z)
|
||||
as_gradient(grad::ColorGradient, α) = grad
|
||||
as_gradient(grad, α) = cgrad(alpha = α)
|
||||
|
||||
# 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]
|
||||
@@ -435,21 +356,6 @@ function plotly_series(plt::Plot, series::Series)
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || series[:markershape] != :none
|
||||
hasline = st in (:path, :path3d)
|
||||
hasfillrange = st in (:path, :scatter, :scattergl) && isa(series[:fillrange], AbstractVector)
|
||||
|
||||
# for surface types, set the data
|
||||
if st in (:heatmap, :contour, :surface, :wireframe)
|
||||
for letter in [:x,:y,:z]
|
||||
d_out[letter] = plotly_surface_data(series, series[letter])
|
||||
end
|
||||
end
|
||||
|
||||
d_out[:colorbar] = KW(:title => sp[:colorbar_title])
|
||||
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
d_out[:zmin], d_out[:zmax] = clims
|
||||
end
|
||||
|
||||
# set the "type"
|
||||
if st in (:path, :scatter, :scattergl)
|
||||
@@ -462,58 +368,33 @@ function plotly_series(plt::Plot, series::Series)
|
||||
if series[:fillrange] == true || series[:fillrange] == 0
|
||||
d_out[:fill] = "tozeroy"
|
||||
d_out[:fillcolor] = rgba_string(series[:fillcolor])
|
||||
elseif isa(series[:fillrange], AbstractVector)
|
||||
d_out[:fill] = "tonexty"
|
||||
d_out[:fillcolor] = rgba_string(series[:fillcolor])
|
||||
elseif !(series[:fillrange] in (false, nothing))
|
||||
warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
|
||||
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(series[:fillrange])")
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
elseif st == :bar
|
||||
d_out[:type] = "bar"
|
||||
d_out[:x], d_out[:y], d_out[:orientation] = if isvertical(series)
|
||||
x, y, "v"
|
||||
else
|
||||
y, x, "h"
|
||||
end
|
||||
d_out[:marker] = KW(:color => rgba_string(series[:fillcolor]))
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:orientation] = isvertical(series) ? "v" : "h"
|
||||
|
||||
elseif st == :heatmap
|
||||
d_out[:type] = "heatmap"
|
||||
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
|
||||
elseif st == :contour
|
||||
d_out[:type] = "contour"
|
||||
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
# d_out[:showscale] = series[:colorbar] != :none
|
||||
d_out[:ncontours] = series[:levels]
|
||||
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
|
||||
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
d_out[:type] = "surface"
|
||||
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
if st == :wireframe
|
||||
d_out[:hidesurface] = true
|
||||
wirelines = KW(
|
||||
:show => true,
|
||||
:color => rgba_string(series[:linecolor]),
|
||||
:highlightwidth => series[:linewidth],
|
||||
)
|
||||
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
|
||||
d_out[:showscale] = false
|
||||
else
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:opacity] = series[:fillalpha]
|
||||
if series[:fill_z] != nothing
|
||||
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
|
||||
end
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
end
|
||||
d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
|
||||
elseif st == :pie
|
||||
d_out[:type] = "pie"
|
||||
@@ -554,10 +435,9 @@ function plotly_series(plt::Plot, series::Series)
|
||||
rgba_string(series[:markercolor])
|
||||
else
|
||||
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
|
||||
grad = as_gradient(series[:markercolor], series[:markeralpha])
|
||||
zmin, zmax = ignorenan_extrema(series[:marker_z])
|
||||
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)
|
||||
[rgba_string(grad[(zi - zmin) / zrange]) for zi in series[:marker_z]]
|
||||
grad = series[:markercolor]
|
||||
zmin, zmax = extrema(series[:marker_z])
|
||||
[rgba_string(grad[(zi - zmin) / (zmax - zmin)]) for zi in series[:marker_z]]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -581,27 +461,15 @@ function plotly_series(plt::Plot, series::Series)
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, series[:hover])
|
||||
|
||||
if hasfillrange
|
||||
# if hasfillrange is true, return two dictionaries (one for original
|
||||
# series, one for series being filled to) instead of one
|
||||
d_out_fillrange = copy(d_out)
|
||||
d_out_fillrange[:y] = series[:fillrange]
|
||||
d_out_fillrange[:showlegend] = false
|
||||
delete!(d_out_fillrange, :fill)
|
||||
delete!(d_out_fillrange, :fillcolor)
|
||||
|
||||
return [d_out_fillrange, d_out]
|
||||
else
|
||||
return [d_out]
|
||||
end
|
||||
[d_out]
|
||||
end
|
||||
|
||||
function plotly_series_shapes(plt::Plot, series::Series)
|
||||
d_outs = []
|
||||
|
||||
|
||||
# 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
|
||||
spidx = plotly_subplot_index(series[:subplot])
|
||||
base_d = KW()
|
||||
@@ -609,7 +477,7 @@ function plotly_series_shapes(plt::Plot, series::Series)
|
||||
base_d[:yaxis] = "y$spidx"
|
||||
base_d[:name] = series[:label]
|
||||
# base_d[:legendgroup] = series[:label]
|
||||
|
||||
|
||||
x, y = plotly_data(series[:x]), plotly_data(series[:y])
|
||||
for (i,rng) in enumerate(iter_segments(x,y))
|
||||
length(rng) < 2 && continue
|
||||
@@ -621,18 +489,18 @@ function plotly_series_shapes(plt::Plot, series::Series)
|
||||
:x => vcat(x[rng], x[rng[1]]),
|
||||
:y => vcat(y[rng], y[rng[1]]),
|
||||
:fill => "tozeroy",
|
||||
:fillcolor => rgba_string(_cycle(series[:fillcolor], i)),
|
||||
:fillcolor => rgba_string(cycle(series[:fillcolor], i)),
|
||||
))
|
||||
if series[:markerstrokewidth] > 0
|
||||
d_out[:line] = KW(
|
||||
:color => rgba_string(_cycle(series[:linecolor], i)),
|
||||
:color => rgba_string(cycle(series[:linecolor], i)),
|
||||
:width => series[:linewidth],
|
||||
:dash => string(series[:linestyle]),
|
||||
)
|
||||
end
|
||||
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, _cycle(series[:hover], i))
|
||||
plotly_hover!(d_out, cycle(series[:hover], i))
|
||||
push!(d_outs, d_out)
|
||||
end
|
||||
d_outs
|
||||
@@ -668,12 +536,8 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _use_remote = Ref(false)
|
||||
|
||||
function html_head(plt::Plot{PlotlyBackend})
|
||||
jsfilename = _use_remote[] ? _plotly_js_path_remote : _plotly_js_path
|
||||
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
|
||||
"<script src=\"$jsfilename\"></script>"
|
||||
"<script src=\"$(Pkg.dir("Plots","deps","plotly-latest.min.js"))\"></script>"
|
||||
end
|
||||
|
||||
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
|
||||
@@ -703,12 +567,11 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function _show(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
|
||||
# show_png_from_html(io, plt)
|
||||
error("png output from the plotly backend is not supported. Please use plotlyjs instead.")
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
|
||||
writemime_png_from_html(io, plt)
|
||||
end
|
||||
|
||||
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend})
|
||||
function _writemime(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
end
|
||||
|
||||
|
||||
+14
-60
@@ -1,29 +1,16 @@
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
|
||||
const _plotlyjs_attr = _plotly_attr
|
||||
const _plotlyjs_seriestype = _plotly_seriestype
|
||||
const _plotlyjs_style = _plotly_style
|
||||
const _plotlyjs_marker = _plotly_marker
|
||||
const _plotlyjs_scale = _plotly_scale
|
||||
supported_args(::PlotlyJSBackend) = supported_args(PlotlyBackend())
|
||||
supported_types(::PlotlyJSBackend) = supported_types(PlotlyBackend())
|
||||
supported_styles(::PlotlyJSBackend) = supported_styles(PlotlyBackend())
|
||||
supported_markers(::PlotlyJSBackend) = supported_markers(PlotlyBackend())
|
||||
supported_scales(::PlotlyJSBackend) = supported_scales(PlotlyBackend())
|
||||
is_subplot_supported(::PlotlyJSBackend) = true
|
||||
is_string_supported(::PlotlyJSBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
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
|
||||
@@ -40,11 +27,7 @@ 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)
|
||||
else
|
||||
PlotlyJS.plot()
|
||||
end
|
||||
PlotlyJS.plot()
|
||||
end
|
||||
|
||||
|
||||
@@ -60,15 +43,10 @@ end
|
||||
|
||||
function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
|
||||
xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,: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(plt.series_list, series),
|
||||
kw
|
||||
KW(xsym => (series.d[:x],), ysym => (series.d[:y],))
|
||||
)
|
||||
end
|
||||
|
||||
@@ -85,40 +63,16 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
|
||||
if isijulia() && !_use_remote[]
|
||||
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
|
||||
else
|
||||
show(io, MIME("text/html"), plt.o)
|
||||
end
|
||||
function _writemime(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
|
||||
writemime(io, MIME("text/html"), plt.o)
|
||||
end
|
||||
|
||||
function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
|
||||
tmpfn = tempname() * "." * ext
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend})
|
||||
tmpfn = tempname() * ".png"
|
||||
PlotlyJS.savefig(plt.o, tmpfn)
|
||||
write(io, read(open(tmpfn)))
|
||||
end
|
||||
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
|
||||
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
|
||||
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
|
||||
|
||||
function write_temp_html(plt::Plot{PlotlyJSBackend})
|
||||
filename = string(tempname(), ".html")
|
||||
savefig(plt, filename)
|
||||
filename
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PlotlyJSBackend})
|
||||
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
|
||||
display(plt.o)
|
||||
else
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function closeall(::PlotlyJSBackend)
|
||||
if !isplotnull() && isa(current().o, PlotlyJS.SyncPlot)
|
||||
close(current().o)
|
||||
end
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
+128
-203
@@ -2,7 +2,7 @@
|
||||
# https://github.com/stevengj/PyPlot.jl
|
||||
|
||||
|
||||
const _pyplot_attr = merge_with_base_supported([
|
||||
supported_args(::PyPlotBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
@@ -17,8 +17,9 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :legendtitle, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z,
|
||||
:line_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
@@ -30,70 +31,49 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
supported_types(::PyPlotBackend) = [
|
||||
:path, :steppre, :steppost, :shape,
|
||||
:scatter, :hexbin, #:histogram2d, :histogram,
|
||||
# :bar,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _pyplot_marker = vcat(_allMarkers, :pixel)
|
||||
const _pyplot_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::PyPlotBackend, shape::Shape) = true
|
||||
supported_styles(::PyPlotBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::PyPlotBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::PyPlotBackend) = [:identity, :ln, :log2, :log10]
|
||||
is_subplot_supported(::PyPlotBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function add_backend_string(::PyPlotBackend)
|
||||
"""
|
||||
if !Plots.is_installed("PyPlot")
|
||||
Pkg.add("PyPlot")
|
||||
end
|
||||
withenv("PYTHON" => "") do
|
||||
Pkg.build("PyPlot")
|
||||
end
|
||||
|
||||
# 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 PyPlot
|
||||
import LaTeXStrings: latexstring
|
||||
append!(Base.Multimedia.displays, otherdisplays)
|
||||
|
||||
export PyPlot
|
||||
const pycolors = PyPlot.pyimport("matplotlib.colors")
|
||||
const pypath = PyPlot.pyimport("matplotlib.path")
|
||||
const mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
|
||||
const pypatches = PyPlot.pyimport("matplotlib.patches")
|
||||
const pyfont = PyPlot.pyimport("matplotlib.font_manager")
|
||||
const pyticker = PyPlot.pyimport("matplotlib.ticker")
|
||||
const pycmap = PyPlot.pyimport("matplotlib.cm")
|
||||
const pynp = PyPlot.pyimport("numpy")
|
||||
pynp["seterr"](invalid="ignore")
|
||||
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
|
||||
const pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
const pyart3d = PyPlot.pyimport("mpl_toolkits.mplot3d.art3d")
|
||||
|
||||
# "support" matplotlib v1.5
|
||||
const set_facecolor_sym = if PyPlot.version < v"2"
|
||||
warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0")
|
||||
:set_axis_bgcolor
|
||||
else
|
||||
:set_facecolor
|
||||
end
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
|
||||
const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
|
||||
const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
|
||||
const pypatches = PyPlot.pywrap(PyPlot.pyimport("matplotlib.patches"))
|
||||
const pyfont = PyPlot.pywrap(PyPlot.pyimport("matplotlib.font_manager"))
|
||||
const pyticker = PyPlot.pywrap(PyPlot.pyimport("matplotlib.ticker"))
|
||||
const pycmap = PyPlot.pywrap(PyPlot.pyimport("matplotlib.cm"))
|
||||
const pynp = PyPlot.pywrap(PyPlot.pyimport("numpy"))
|
||||
pynp.seterr(invalid="ignore")
|
||||
const pytransforms = PyPlot.pywrap(PyPlot.pyimport("matplotlib.transforms"))
|
||||
const pycollections = PyPlot.pywrap(PyPlot.pyimport("matplotlib.collections"))
|
||||
const pyart3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d.art3d"))
|
||||
end
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -109,7 +89,7 @@ end
|
||||
|
||||
# function py_colormap(c::ColorGradient, α=nothing)
|
||||
# pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values]
|
||||
# pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
|
||||
# end
|
||||
|
||||
# # convert vectors and ColorVectors to standard ColorGradients
|
||||
@@ -126,16 +106,14 @@ py_color(grad::ColorGradient) = py_color(grad.colors)
|
||||
|
||||
function py_colormap(grad::ColorGradient)
|
||||
pyvals = [(z, py_color(grad[z])) for z in grad.values]
|
||||
cm = pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
cm[:set_bad](color=(0,0,0,0.0), alpha=0.0)
|
||||
cm
|
||||
pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals)
|
||||
end
|
||||
py_colormap(c) = py_colormap(cgrad())
|
||||
|
||||
|
||||
function py_shading(c, z)
|
||||
cmap = py_colormap(c)
|
||||
ls = pycolors["LightSource"](270,45)
|
||||
function py_shading(c, z, α=nothing)
|
||||
cmap = py_colormap(c, α)
|
||||
ls = pycolors.pymember("LightSource")(270,45)
|
||||
ls[:shade](z, cmap, vert_exag=0.1, blend_mode="soft")
|
||||
end
|
||||
|
||||
@@ -151,7 +129,7 @@ function py_linestyle(seriestype::Symbol, linestyle::Symbol)
|
||||
end
|
||||
|
||||
function py_marker(marker::Shape)
|
||||
x, y = coords(marker)
|
||||
x, y = shape_coords(marker)
|
||||
n = length(x)
|
||||
mat = zeros(n+1,2)
|
||||
for i=1:n
|
||||
@@ -159,7 +137,7 @@ function py_marker(marker::Shape)
|
||||
mat[i,2] = y[i]
|
||||
end
|
||||
mat[n+1,:] = mat[1,:]
|
||||
pypath["Path"](mat)
|
||||
pypath.pymember("Path")(mat)
|
||||
end
|
||||
|
||||
const _path_MOVETO = UInt8(1)
|
||||
@@ -185,7 +163,7 @@ const _path_CLOSEPOLY = UInt8(79)
|
||||
# lastnan = nan
|
||||
# end
|
||||
# codes[n+1] = _path_CLOSEPOLY
|
||||
# pypath["Path"](mat, codes)
|
||||
# pypath.pymember("Path")(mat, codes)
|
||||
# end
|
||||
|
||||
# get the marker shape
|
||||
@@ -196,13 +174,12 @@ function py_marker(marker::Symbol)
|
||||
marker == :diamond && return "D"
|
||||
marker == :utriangle && return "^"
|
||||
marker == :dtriangle && return "v"
|
||||
marker == :+ && return "+"
|
||||
marker == :x && return "x"
|
||||
# marker == :cross && return "+"
|
||||
# marker == :xcross && return "x"
|
||||
marker == :star5 && return "*"
|
||||
marker == :pentagon && return "p"
|
||||
marker == :hexagon && return "h"
|
||||
marker == :octagon && return "8"
|
||||
marker == :pixel && return ","
|
||||
haskey(_shapes, marker) && return py_marker(_shapes[marker])
|
||||
|
||||
warn("Unknown marker $marker")
|
||||
@@ -227,22 +204,16 @@ function py_stepstyle(seriestype::Symbol)
|
||||
return "default"
|
||||
end
|
||||
|
||||
function py_fillstepstyle(seriestype::Symbol)
|
||||
seriestype == :steppost && return "post"
|
||||
seriestype == :steppre && return "pre"
|
||||
return nothing
|
||||
end
|
||||
|
||||
# # untested... return a FontProperties object from a Plots.Font
|
||||
# function py_font(font::Font)
|
||||
# pyfont["FontProperties"](
|
||||
# pyfont.pymember("FontProperties")(
|
||||
# family = font.family,
|
||||
# size = font.size
|
||||
# )
|
||||
# end
|
||||
|
||||
function get_locator_and_formatter(vals::AVec)
|
||||
pyticker["FixedLocator"](1:length(vals)), pyticker["FixedFormatter"](vals)
|
||||
pyticker.pymember("FixedLocator")(1:length(vals)), pyticker.pymember("FixedFormatter")(vals)
|
||||
end
|
||||
|
||||
function add_pyfixedformatter(cbar, vals::AVec)
|
||||
@@ -263,12 +234,6 @@ function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
end
|
||||
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
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
|
||||
@@ -379,7 +344,7 @@ function py_bbox_title(ax)
|
||||
end
|
||||
|
||||
function py_dpi_scale(plt::Plot{PyPlotBackend}, ptsz)
|
||||
ptsz * plt[:dpi] / DPI
|
||||
ptsz * DPI / plt[:dpi]
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -433,6 +398,10 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
sp = series[:subplot]
|
||||
ax = sp.o
|
||||
|
||||
if !(st in supported_types(plt.backend))
|
||||
error("seriestype $(st) is unsupported in PyPlot. Choose from: $(supported_types(plt.backend))")
|
||||
end
|
||||
|
||||
# PyPlot doesn't handle mismatched x/y
|
||||
fix_xy_lengths!(plt, series)
|
||||
|
||||
@@ -460,9 +429,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
error("Only numbers and vectors are supported with levels keyword")
|
||||
end
|
||||
|
||||
# add custom frame shapes to markershape?
|
||||
series_annotations_shapes!(series, :xy)
|
||||
|
||||
# for each plotting command, optionally build and add a series handle to the list
|
||||
|
||||
# line plot
|
||||
@@ -492,35 +458,28 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
:linewidth => py_dpi_scale(plt, series[:linewidth]),
|
||||
:linestyle => py_linestyle(st, series[:linestyle])
|
||||
)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
extrakw = KW()
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
kw[:norm] = pycolors["Normalize"](; extrakw...)
|
||||
end
|
||||
lz = collect(series[:line_z])
|
||||
handle = if is3d(st)
|
||||
for rng in iter_segments(x, y, z)
|
||||
length(rng) < 2 && continue
|
||||
push!(segments, [(_cycle(x,i),_cycle(y,i),_cycle(z,i)) for i in rng])
|
||||
push!(segments, [(cycle(x,i),cycle(y,i),cycle(z,i)) for i in rng])
|
||||
end
|
||||
# for i=1:n
|
||||
# segments[i] = [(_cycle(x,i), _cycle(y,i), _cycle(z,i)), (_cycle(x,i+1), _cycle(y,i+1), _cycle(z,i+1))]
|
||||
# segments[i] = [(cycle(x,i), cycle(y,i), cycle(z,i)), (cycle(x,i+1), cycle(y,i+1), cycle(z,i+1))]
|
||||
# end
|
||||
lc = pyart3d["Line3DCollection"](segments; kw...)
|
||||
lc = pyart3d.Line3DCollection(segments; kw...)
|
||||
lc[:set_array](lz)
|
||||
ax[:add_collection3d](lc, zs=z) #, zdir='y')
|
||||
lc
|
||||
else
|
||||
for rng in iter_segments(x, y)
|
||||
length(rng) < 2 && continue
|
||||
push!(segments, [(_cycle(x,i),_cycle(y,i)) for i in rng])
|
||||
push!(segments, [(cycle(x,i),cycle(y,i)) for i in rng])
|
||||
end
|
||||
# for i=1:n
|
||||
# segments[i] = [(_cycle(x,i), _cycle(y,i)), (_cycle(x,i+1), _cycle(y,i+1))]
|
||||
# segments[i] = [(cycle(x,i), cycle(y,i)), (cycle(x,i+1), cycle(y,i+1))]
|
||||
# end
|
||||
lc = pycollections["LineCollection"](segments; kw...)
|
||||
lc = pycollections.LineCollection(segments; kw...)
|
||||
lc[:set_array](lz)
|
||||
ax[:add_collection](lc)
|
||||
lc
|
||||
@@ -578,46 +537,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
else
|
||||
xyargs
|
||||
end
|
||||
|
||||
if isa(series[:markershape], AbstractVector{Shape})
|
||||
# this section will create one scatter per data point to accomodate the
|
||||
# vector of shapes
|
||||
handle = []
|
||||
x,y = xyargs
|
||||
shapes = series[:markershape]
|
||||
msc = py_markerstrokecolor(series)
|
||||
lw = py_dpi_scale(plt, series[:markerstrokewidth])
|
||||
for i=1:length(y)
|
||||
extrakw[:c] = if series[:marker_z] == nothing
|
||||
py_color_fix(py_color(_cycle(series[:markercolor],i)), x)
|
||||
else
|
||||
extrakw[:c]
|
||||
end
|
||||
|
||||
push!(handle, ax[:scatter](_cycle(x,i), _cycle(y,i);
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = py_marker(_cycle(shapes,i)),
|
||||
s = py_dpi_scale(plt, _cycle(series[:markersize],i) .^ 2),
|
||||
edgecolors = msc,
|
||||
linewidths = lw,
|
||||
extrakw...
|
||||
))
|
||||
end
|
||||
push!(handles, handle)
|
||||
else
|
||||
# do a normal scatter plot
|
||||
handle = ax[:scatter](xyargs...;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = py_marker(series[:markershape]),
|
||||
s = py_dpi_scale(plt, series[:markersize] .^ 2),
|
||||
edgecolors = py_markerstrokecolor(series),
|
||||
linewidths = py_dpi_scale(plt, series[:markerstrokewidth]),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
end
|
||||
handle = ax[:scatter](xyargs...;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = py_marker(series[:markershape]),
|
||||
s = py_dpi_scale(plt, series[:markersize] .^ 2),
|
||||
edgecolors = py_markerstrokecolor(series),
|
||||
linewidths = py_dpi_scale(plt, series[:markerstrokewidth]),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
end
|
||||
|
||||
if st == :hexbin
|
||||
@@ -683,21 +612,21 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
x = repmat(x', length(y), 1)
|
||||
y = repmat(y, 1, length(series[:x]))
|
||||
end
|
||||
# z = z'
|
||||
z = transpose_z(series, z)
|
||||
if st == :surface
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
if series[:fill_z] != nothing
|
||||
# the surface colors are different than z-value
|
||||
extrakw[:facecolors] = py_shading(series[:fillcolor], transpose_z(series, series[:fill_z].surf))
|
||||
if series[:marker_z] != nothing
|
||||
extrakw[:facecolors] = py_shading(series[:fillcolor], series[:marker_z], series[:fillalpha])
|
||||
extrakw[:shade] = false
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
else
|
||||
extrakw[:cmap] = py_fillcolormap(series)
|
||||
needs_colorbar = true
|
||||
end
|
||||
needs_colorbar = true
|
||||
end
|
||||
handle = ax[st == :surface ? :plot_surface : :plot_wireframe](x, y, z;
|
||||
label = series[:label],
|
||||
@@ -713,11 +642,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# contours on the axis planes
|
||||
if series[:contours]
|
||||
for (zdir,mat) in (("x",x), ("y",y), ("z",z))
|
||||
offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat)
|
||||
offset = (zdir == "y" ? maximum : minimum)(mat)
|
||||
handle = ax[:contourf](x, y, z, levelargs...;
|
||||
zdir = zdir,
|
||||
cmap = py_fillcolormap(series),
|
||||
offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat) # where to draw the contour plane
|
||||
offset = (zdir == "y" ? maximum : minimum)(mat) # where to draw the contour plane
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
@@ -776,48 +705,69 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :heatmap
|
||||
x, y, z = heatmap_edges(x, sp[:xaxis][:scale]), heatmap_edges(y, sp[:yaxis][:scale]), transpose_z(series, z.surf)
|
||||
|
||||
expand_extrema!(sp[:xaxis], x)
|
||||
expand_extrema!(sp[:yaxis], y)
|
||||
x, y, z = heatmap_edges(x), heatmap_edges(y), transpose_z(series, z.surf)
|
||||
# if !(eltype(z) <: Number)
|
||||
# z, discrete_colorbar_values = indices_and_unique_values(z)
|
||||
# end
|
||||
dvals = sp[:zaxis][:discrete_values]
|
||||
if !isempty(dvals)
|
||||
discrete_colorbar_values = dvals
|
||||
end
|
||||
|
||||
clims = sp[:clims]
|
||||
zmin, zmax = ignorenan_extrema(z)
|
||||
extrakw[:vmin] = (is_2tuple(clims) && isfinite(clims[1])) ? clims[1] : zmin
|
||||
extrakw[:vmax] = (is_2tuple(clims) && isfinite(clims[2])) ? clims[2] : zmax
|
||||
|
||||
handle = ax[:pcolormesh](x, y, py_mask_nans(z);
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
|
||||
handle = ax[:pcolormesh](x, y, z;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
cmap = py_fillcolormap(series),
|
||||
# edgecolors = (series[:linewidth] > 0 ? py_linecolor(series) : "face"),
|
||||
edgecolors = (series[:linewidth] > 0 ? py_linecolor(series) : "face"),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
|
||||
# TODO: this should probably be handled generically
|
||||
# expand extrema... handle is a QuadMesh object
|
||||
for path in handle[:properties]()["paths"]
|
||||
verts = path[:vertices]
|
||||
xmin, ymin = minimum(verts, 1)
|
||||
xmax, ymax = maximum(verts, 1)
|
||||
expand_extrema!(sp, xmin, xmax, ymin, ymax)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if st == :shape
|
||||
handle = []
|
||||
for (i,rng) in enumerate(iter_segments(x, y))
|
||||
if length(rng) > 1
|
||||
path = pypath["Path"](hcat(x[rng], y[rng]))
|
||||
patches = pypatches["PathPatch"](
|
||||
path = pypath.pymember("Path")(hcat(x[rng], y[rng]))
|
||||
patches = pypatches.pymember("PathPatch")(
|
||||
path;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
edgecolor = py_color(_cycle(series[:linecolor], i)),
|
||||
facecolor = py_color(_cycle(series[:fillcolor], i)),
|
||||
edgecolor = py_color(cycle(series[:linecolor], i)),
|
||||
facecolor = py_color(cycle(series[:fillcolor], i)),
|
||||
linewidth = py_dpi_scale(plt, series[:linewidth]),
|
||||
fill = true
|
||||
)
|
||||
push!(handle, ax[:add_patch](patches))
|
||||
end
|
||||
end
|
||||
# path = py_path(x, y)
|
||||
# patches = pypatches.pymember("PathPatch")(path;
|
||||
# label = series[:label],
|
||||
# zorder = series[:series_plotindex],
|
||||
# edgecolor = py_linecolor(series),
|
||||
# facecolor = py_fillcolor(series),
|
||||
# linewidth = py_dpi_scale(plt, series[:linewidth]),
|
||||
# fill = true
|
||||
# )
|
||||
# handle = ax[:add_patch](patches)
|
||||
push!(handles, handle)
|
||||
end
|
||||
|
||||
@@ -831,7 +781,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# # expand extrema... get list of Wedge objects
|
||||
# for wedge in handle
|
||||
# path = wedge[:get_path]()
|
||||
# for
|
||||
# for
|
||||
lim = 1.1
|
||||
expand_extrema!(sp, -lim, lim, -lim, lim)
|
||||
end
|
||||
@@ -859,9 +809,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# note: the colorbar axis is positioned independently from the subplot axis
|
||||
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])
|
||||
sp.attr[:cbar_handle] = cb
|
||||
sp.attr[:cbar_handle] = fig[:colorbar](handle; cax = cbax, kw...)
|
||||
sp.attr[:cbar_ax] = cbax
|
||||
end
|
||||
|
||||
@@ -880,19 +828,13 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
dim1, expand_data(fillrange[1], n), expand_data(fillrange[2], n)
|
||||
end
|
||||
|
||||
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
|
||||
handle = ax[f](args...;
|
||||
zorder = series[:series_plotindex],
|
||||
facecolor = py_fillcolor(series),
|
||||
linewidths = 0
|
||||
)
|
||||
push!(handles, handle)
|
||||
end
|
||||
|
||||
# this is all we need to add the series_annotations text
|
||||
anns = series[:series_annotations]
|
||||
for (xi,yi,str,fnt) in EachAnn(anns, x, y)
|
||||
py_add_annotations(sp, xi, yi, PlotText(str, fnt))
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
@@ -929,19 +871,17 @@ end
|
||||
function py_compute_axis_minval(axis::Axis)
|
||||
# compute the smallest absolute value for the log scale's linear threshold
|
||||
minval = 1.0
|
||||
sps = axis.sps
|
||||
for sp in sps
|
||||
for series in series_list(sp)
|
||||
v = series.d[axis[:letter]]
|
||||
if !isempty(v)
|
||||
minval = NaNMath.min(minval, ignorenan_minimum(abs.(v)))
|
||||
end
|
||||
sp = axis.sp
|
||||
for series in series_list(axis.sp)
|
||||
v = series.d[axis[:letter]]
|
||||
if !isempty(v)
|
||||
minval = min(minval, minimum(abs(v)))
|
||||
end
|
||||
end
|
||||
|
||||
# now if the axis limits go to a smaller abs value, use that instead
|
||||
vmin, vmax = axis_limits(axis)
|
||||
minval = NaNMath.min(minval, abs(vmin), abs(vmax))
|
||||
minval = min(minval, abs(vmin), abs(vmax))
|
||||
|
||||
minval
|
||||
end
|
||||
@@ -962,7 +902,7 @@ function py_set_scale(ax, axis::Axis)
|
||||
elseif scale == :log10
|
||||
10
|
||||
end
|
||||
kw[Symbol(:linthresh,letter)] = NaNMath.max(1e-16, py_compute_axis_minval(axis))
|
||||
kw[Symbol(:linthresh,letter)] = max(1e-16, py_compute_axis_minval(axis))
|
||||
"symlog"
|
||||
end
|
||||
func(arg; kw...)
|
||||
@@ -993,9 +933,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
fig[:clear]()
|
||||
dpi = plt[:dpi]
|
||||
fig[:set_size_inches](w/dpi, h/dpi, forward = true)
|
||||
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
|
||||
fig[:set_facecolor](py_color(plt[:background_color_outside]))
|
||||
fig[:set_dpi](dpi)
|
||||
|
||||
|
||||
# resize the window
|
||||
PyPlot.plt[:get_current_fig_manager]()[:resize](w, h)
|
||||
|
||||
@@ -1033,7 +973,6 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
ax[func][:set_text](sp[:title])
|
||||
ax[func][:set_fontsize](py_dpi_scale(plt, sp[:titlefont].pointsize))
|
||||
ax[func][:set_family](sp[:titlefont].family)
|
||||
ax[func][:set_color](py_color(sp[:foreground_color_title]))
|
||||
# ax[:set_title](sp[:title], loc = loc)
|
||||
end
|
||||
@@ -1041,15 +980,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
# axis attributes
|
||||
for letter in (:x, :y, :z)
|
||||
axissym = Symbol(letter, :axis)
|
||||
haskey(ax, axissym) || continue
|
||||
axis = sp[axissym]
|
||||
pyaxis = ax[axissym]
|
||||
if axis[:mirror] && letter != :z
|
||||
pos = letter == :x ? "top" : "right"
|
||||
pyaxis[:set_label_position](pos) # the guides
|
||||
pyaxis[:set_ticks_position]("both") # the hash marks
|
||||
pyaxis[Symbol(:tick_, pos)]() # the tick labels
|
||||
end
|
||||
haskey(ax, axissym) || continue
|
||||
py_set_scale(ax, axis)
|
||||
py_set_lims(ax, axis)
|
||||
py_set_ticks(ax, get_ticks(axis), letter)
|
||||
@@ -1057,16 +989,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
if get(axis.d, :flip, false)
|
||||
ax[Symbol("invert_", letter, "axis")]()
|
||||
end
|
||||
pyaxis[:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefont].pointsize))
|
||||
pyaxis[:label][:set_family](axis[:guidefont].family)
|
||||
ax[axissym][:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefont].pointsize))
|
||||
for lab in ax[Symbol("get_", letter, "ticklabels")]()
|
||||
lab[:set_fontsize](py_dpi_scale(plt, axis[:tickfont].pointsize))
|
||||
lab[:set_family](axis[:tickfont].family)
|
||||
lab[:set_rotation](axis[:rotation])
|
||||
end
|
||||
if sp[:grid]
|
||||
fgcolor = py_color(sp[:foreground_color_grid])
|
||||
pyaxis[:grid](true, color = fgcolor, linestyle = ":")
|
||||
ax[axissym][:grid](true, color = fgcolor)
|
||||
ax[:set_axisbelow](true)
|
||||
end
|
||||
py_set_axis_colors(ax, axis)
|
||||
@@ -1082,7 +1012,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
py_add_legend(plt, sp, ax)
|
||||
|
||||
# this sets the bg color inside the grid
|
||||
ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
|
||||
ax[:set_axis_bgcolor](py_color(sp[:background_color_inside]))
|
||||
end
|
||||
py_drawfig(fig)
|
||||
end
|
||||
@@ -1114,7 +1044,7 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
|
||||
# optionally add the width of colorbar labels and colorbar to rightpad
|
||||
if haskey(sp.attr, :cbar_ax)
|
||||
bb = py_bbox(sp.attr[:cbar_handle][:ax][:get_yticklabels]())
|
||||
sp.attr[:cbar_width] = _cbar_width + width(bb) + 2.3mm + (sp[:colorbar_title] == "" ? 0px : 30px)
|
||||
sp.attr[:cbar_width] = _cbar_width + width(bb) + 1mm
|
||||
rightpad = rightpad + sp.attr[:cbar_width]
|
||||
end
|
||||
|
||||
@@ -1174,7 +1104,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
# add a line/marker and a label
|
||||
push!(handles, if series[:seriestype] == :shape
|
||||
PyPlot.plt[:Line2D]((0,1),(0,0),
|
||||
color = py_color(_cycle(series[:fillcolor],1)),
|
||||
color = py_color(cycle(series[:fillcolor],1)),
|
||||
linewidth = py_dpi_scale(plt, 4)
|
||||
)
|
||||
else
|
||||
@@ -1191,20 +1121,18 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
loc = get(_pyplot_legend_pos, leg, "best"),
|
||||
scatterpoints = 1,
|
||||
fontsize = py_dpi_scale(plt, sp[:legendfont].pointsize)
|
||||
# family = sp[:legendfont].family
|
||||
# framealpha = 0.6
|
||||
)
|
||||
leg[:set_zorder](1000)
|
||||
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
|
||||
|
||||
fgcolor = py_color(sp[:foreground_color_legend])
|
||||
for txt in leg[:get_texts]()
|
||||
PyPlot.plt[:setp](txt, color = fgcolor, family = sp[:legendfont].family)
|
||||
PyPlot.plt[:setp](txt, color = fgcolor)
|
||||
end
|
||||
|
||||
# set some legend properties
|
||||
frame = leg[:get_frame]()
|
||||
frame[set_facecolor_sym](py_color(sp[:background_color_legend]))
|
||||
frame[:set_facecolor](py_color(sp[:background_color_legend]))
|
||||
frame[:set_edgecolor](fgcolor)
|
||||
end
|
||||
end
|
||||
@@ -1228,8 +1156,7 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
|
||||
if haskey(sp.attr, :cbar_ax)
|
||||
cbw = sp.attr[:cbar_width]
|
||||
# this is the bounding box of just the colors of the colorbar (not labels)
|
||||
has_toplabel = sp[:zaxis][:extrema].emax >= 1e7
|
||||
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox) + (has_toplabel ? 4mm : 2mm), _cbar_width-1mm, height(sp.bbox) - (has_toplabel ? 6mm : 4mm))
|
||||
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox)+2mm, _cbar_width-1mm, height(sp.bbox)-4mm)
|
||||
pcts = bbox_to_pcts(cb_bbox, figw, figh)
|
||||
sp.attr[:cbar_ax][:set_position](pcts)
|
||||
end
|
||||
@@ -1257,18 +1184,16 @@ const _pyplot_mimeformats = Dict(
|
||||
|
||||
|
||||
for (mime, fmt) in _pyplot_mimeformats
|
||||
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PyPlotBackend})
|
||||
@eval function _writemime(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PyPlotBackend})
|
||||
fig = plt.o
|
||||
fig[:canvas][:print_figure](
|
||||
fig.o[:canvas][:print_figure](
|
||||
io,
|
||||
format=$fmt,
|
||||
# bbox_inches = "tight",
|
||||
# figsize = map(px2inch, plt[:size]),
|
||||
facecolor = fig[:get_facecolor](),
|
||||
facecolor = fig.o[:get_facecolor](),
|
||||
edgecolor = "none",
|
||||
dpi = plt[:dpi]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
closeall(::PyPlotBackend) = PyPlot.plt[:close]("all")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
|
||||
supported_attrs(::QwtBackend) = merge_with_base_supported([
|
||||
supported_args(::QwtBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:linecolor,
|
||||
:fillrange,
|
||||
@@ -39,7 +39,7 @@ end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
const _qwtAliases = KW(
|
||||
@compat const _qwtAliases = KW(
|
||||
:bins => :heatmap_n,
|
||||
:fillrange => :fillto,
|
||||
:linewidth => :width,
|
||||
@@ -133,7 +133,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
|
||||
w = plt.o.widget
|
||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
||||
|
||||
if typeof(lims) <: Union{Tuple,AVec} && length(lims) == 2
|
||||
if typeof(lims) <: @compat(Union{Tuple,AVec}) && length(lims) == 2
|
||||
if isx
|
||||
plt.o.autoscale_x = false
|
||||
else
|
||||
@@ -211,14 +211,14 @@ function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
|
||||
function createQwtAnnotation(plt::Plot, x, y, val::@compat(AbstractString))
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
marker[:setValue](x, y)
|
||||
marker[:setLabel](Qwt.QWT.QwtText(val))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createQwtAnnotation(plt, ann...)
|
||||
end
|
||||
@@ -242,6 +242,8 @@ end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# savepng(::QwtBackend, plt::AbstractPlot, fn::@compat(AbstractString), args...) = Qwt.savepng(plt.o, fn)
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# # create the underlying object (each backend will do this differently)
|
||||
@@ -280,13 +282,13 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
|
||||
write(io, readall("/tmp/dfskjdhfkh.png"))
|
||||
end
|
||||
|
||||
# function Base.show(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
|
||||
# function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
|
||||
# for plt in subplt.plts
|
||||
# Qwt.refresh(plt.o)
|
||||
# end
|
||||
@@ -67,7 +67,7 @@ end
|
||||
# "image/png" => "png",
|
||||
# "application/postscript" => "ps",
|
||||
# "image/svg+xml" => "svg"
|
||||
function _show(io::IO, ::MIME"image/png", plt::Plot{[PkgName]Backend})
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::Plot{[PkgName]Backend})
|
||||
end
|
||||
|
||||
# Display/show the plot (open a GUI window, or browser page, for example).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
supported_args(::UnicodePlotsBackend) = merge_with_base_supported([
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor,
|
||||
@@ -12,30 +12,21 @@ const _unicodeplots_attr = merge_with_base_supported([
|
||||
:title,
|
||||
:guide, :lims,
|
||||
])
|
||||
const _unicodeplots_seriestype = [
|
||||
supported_types(::UnicodePlotsBackend) = [
|
||||
:path, :scatter,
|
||||
# :bar,
|
||||
:shape,
|
||||
:histogram2d,
|
||||
:spy
|
||||
:histogram2d
|
||||
]
|
||||
const _unicodeplots_style = [:auto, :solid]
|
||||
const _unicodeplots_marker = [:none, :auto, :circle]
|
||||
const _unicodeplots_scale = [:identity]
|
||||
supported_styles(::UnicodePlotsBackend) = [:auto, :solid]
|
||||
supported_markers(::UnicodePlotsBackend) = [:none, :auto, :circle]
|
||||
supported_scales(::UnicodePlotsBackend) = [:identity]
|
||||
is_subplot_supported(::UnicodePlotsBackend) = true
|
||||
|
||||
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warnOnUnsupported_args(::UnicodePlotsBackend, d::KW) = nothing
|
||||
warnOnUnsupported_args(pkg::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
|
||||
@@ -45,18 +36,6 @@ end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
const _canvas_type = Ref(:auto)
|
||||
|
||||
function _canvas_map()
|
||||
KW(
|
||||
:braille => UnicodePlots.BrailleCanvas,
|
||||
:ascii => UnicodePlots.AsciiCanvas,
|
||||
:block => UnicodePlots.BlockCanvas,
|
||||
:dot => UnicodePlots.DotCanvas,
|
||||
:density => UnicodePlots.DensityCanvas,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
|
||||
function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
@@ -78,33 +57,7 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
y = Float64[ylim[1]]
|
||||
|
||||
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
|
||||
ct = _canvas_type[]
|
||||
canvas_type = if ct == :auto
|
||||
isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
|
||||
else
|
||||
_canvas_map()[ct]
|
||||
end
|
||||
|
||||
# special handling for spy
|
||||
if length(sp.series_list) == 1
|
||||
series = sp.series_list[1]
|
||||
if series[:seriestype] == :spy
|
||||
push!(plt.o, UnicodePlots.spy(
|
||||
series[:z].surf,
|
||||
width = width,
|
||||
height = height,
|
||||
title = sp[:title],
|
||||
canvas = canvas_type
|
||||
))
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
# # make it a bar canvas if plotting bar
|
||||
# if any(series -> series[:seriestype] == :bar, series_list(sp))
|
||||
# canvas_type = UnicodePlots.BarplotGraphics
|
||||
# end
|
||||
|
||||
canvas_type = isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
|
||||
o = UnicodePlots.Plot(x, y, canvas_type;
|
||||
width = width,
|
||||
height = height,
|
||||
@@ -142,10 +95,6 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif st == :scatter || d[:markershape] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
# elseif st == :bar
|
||||
# func = UnicodePlots.barplot!
|
||||
elseif st == :shape
|
||||
func = UnicodePlots.lineplot!
|
||||
else
|
||||
error("Linestyle $st not supported by UnicodePlots")
|
||||
end
|
||||
@@ -158,13 +107,12 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
|
||||
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
|
||||
|
||||
# add the series
|
||||
x, y = Plots.unzip(collect(filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
|
||||
func(o, x, y; color = color, name = label)
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# since this is such a hack, it's only callable using `png`... should error during normal `show`
|
||||
# since this is such a hack, it's only callable using `png`... should error during normal `writemime`
|
||||
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
|
||||
fn = addExtension(fn, "png")
|
||||
|
||||
@@ -173,7 +121,7 @@ function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
|
||||
gui(plt)
|
||||
|
||||
# @osx_only begin
|
||||
@static if is_apple()
|
||||
@compat @static if is_apple()
|
||||
# BEGIN HACK
|
||||
|
||||
# wait while the plot gets drawn
|
||||
@@ -200,7 +148,7 @@ function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
|
||||
rebuildUnicodePlot!(plt, div(w, 10), div(h, 20))
|
||||
end
|
||||
|
||||
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
|
||||
function _writemime(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
|
||||
unicodeplots_rebuild(plt)
|
||||
map(show, plt.o)
|
||||
nothing
|
||||
@@ -212,3 +160,4 @@ function _display(plt::Plot{UnicodePlotsBackend})
|
||||
map(show, plt.o)
|
||||
nothing
|
||||
end
|
||||
|
||||
|
||||
+5
-5
@@ -20,14 +20,14 @@ function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr
|
||||
end
|
||||
|
||||
function open_browser_window(filename::AbstractString)
|
||||
@static if is_apple()
|
||||
@compat @static if is_apple()
|
||||
return run(`open $(filename)`)
|
||||
end
|
||||
@static if is_linux() || is_bsd() # is_bsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
|
||||
@compat @static if is_linux()
|
||||
return run(`xdg-open $(filename)`)
|
||||
end
|
||||
@static if is_windows()
|
||||
return run(`$(ENV["COMSPEC"]) /c start "" "$(filename)"`)
|
||||
@compat @static if is_windows()
|
||||
return run(`$(ENV["COMSPEC"]) /c start $(filename)`)
|
||||
end
|
||||
warn("Unknown OS... cannot open browser window.")
|
||||
end
|
||||
@@ -51,7 +51,7 @@ function html_to_png(html_fn, png_fn, w, h)
|
||||
run(`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`)
|
||||
end
|
||||
|
||||
function show_png_from_html(io::IO, plt::AbstractPlot)
|
||||
function writemime_png_from_html(io::IO, plt::AbstractPlot)
|
||||
# write html to a temporary file
|
||||
html_fn = write_temp_html(plt)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
supported_attrs(::WinstonBackend) = merge_with_base_supported([
|
||||
supported_args(::WinstonBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:linecolor,
|
||||
:fillrange,
|
||||
@@ -44,13 +44,13 @@ end
|
||||
|
||||
|
||||
## dictionaries for conversion of Plots.jl names to Winston ones.
|
||||
const winston_linestyle = KW(:solid=>"solid",
|
||||
@compat const winston_linestyle = KW(:solid=>"solid",
|
||||
:dash=>"dash",
|
||||
:dot=>"dotted",
|
||||
:dashdot=>"dotdashed"
|
||||
)
|
||||
|
||||
const winston_marker = KW(:none=>".",
|
||||
@compat const winston_marker = KW(:none=>".",
|
||||
:rect => "square",
|
||||
:circle=>"circle",
|
||||
:diamond=>"diamond",
|
||||
@@ -185,7 +185,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _winstonNames = KW(
|
||||
@compat const _winstonNames = KW(
|
||||
:xlims => :xrange,
|
||||
:ylims => :yrange,
|
||||
:xscale => :xlog,
|
||||
@@ -213,11 +213,11 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::AbstractString)
|
||||
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::@compat(AbstractString))
|
||||
Winston.text(x, y, val)
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createWinstonAnnotationObject(plt, ann...)
|
||||
end
|
||||
@@ -238,10 +238,10 @@ function addWinstonLegend(plt::Plot, wplt)
|
||||
end
|
||||
end
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
addWinstonLegend(plt, wplt)
|
||||
show(io, "image/png", wplt)
|
||||
writemime(io, "image/png", wplt)
|
||||
end
|
||||
|
||||
|
||||
+78
-243
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
const P2 = FixedSizeArrays.Vec{2,Float64}
|
||||
const P3 = FixedSizeArrays.Vec{3,Float64}
|
||||
typealias P2 FixedSizeArrays.Vec{2,Float64}
|
||||
typealias P3 FixedSizeArrays.Vec{3,Float64}
|
||||
|
||||
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))
|
||||
@@ -23,24 +23,21 @@ immutable Shape
|
||||
# end
|
||||
end
|
||||
Shape(verts::AVec) = Shape(unzip(verts)...)
|
||||
Shape(s::Shape) = deepcopy(s)
|
||||
|
||||
get_xs(shape::Shape) = shape.x
|
||||
get_ys(shape::Shape) = shape.y
|
||||
vertices(shape::Shape) = collect(zip(shape.x, shape.y))
|
||||
|
||||
#deprecated
|
||||
@deprecate shape_coords coords
|
||||
|
||||
function coords(shape::Shape)
|
||||
function shape_coords(shape::Shape)
|
||||
shape.x, shape.y
|
||||
end
|
||||
|
||||
function coords(shapes::AVec{Shape})
|
||||
function shape_coords(shapes::AVec{Shape})
|
||||
length(shapes) == 0 && return zeros(0), zeros(0)
|
||||
xs = map(get_xs, shapes)
|
||||
ys = map(get_ys, shapes)
|
||||
x, y = map(copy, coords(shapes[1]))
|
||||
x, y = map(copy, shape_coords(shapes[1]))
|
||||
for shape in shapes[2:end]
|
||||
nanappend!(x, shape.x)
|
||||
nanappend!(y, shape.y)
|
||||
@@ -50,7 +47,7 @@ end
|
||||
|
||||
"get an array of tuples of points on a circle with radius `r`"
|
||||
function partialcircle(start_θ, end_θ, n = 20, r=1)
|
||||
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
|
||||
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
|
||||
end
|
||||
|
||||
"interleave 2 vectors into each other (like a zipper's teeth)"
|
||||
@@ -75,13 +72,13 @@ function makestar(n; offset = -0.5, radius = 1.0)
|
||||
z2 = z1 + π / (n)
|
||||
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
|
||||
Shape(weave(outercircle, innercircle))
|
||||
Shape(weave(outercircle, innercircle)[1:end-2])
|
||||
end
|
||||
|
||||
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
|
||||
function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
z = offset * π
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius))
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius)[1:end-1])
|
||||
end
|
||||
|
||||
|
||||
@@ -91,7 +88,7 @@ function makecross(; offset = -0.5, radius = 1.0)
|
||||
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
|
||||
Shape(weave(outercircle, innercircle,
|
||||
ordering=Vector[outercircle,innercircle,outercircle]))
|
||||
ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
|
||||
end
|
||||
|
||||
|
||||
@@ -113,8 +110,6 @@ const _shape_keys = Symbol[
|
||||
:xcross,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:rtriangle,
|
||||
:ltriangle,
|
||||
:pentagon,
|
||||
:heptagon,
|
||||
:octagon,
|
||||
@@ -124,18 +119,14 @@ const _shape_keys = Symbol[
|
||||
:star8,
|
||||
:vline,
|
||||
:hline,
|
||||
:+,
|
||||
:x,
|
||||
]
|
||||
|
||||
const _shapes = KW(
|
||||
:circle => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
:utriangle => makeshape(3, offset=0.5),
|
||||
:dtriangle => makeshape(3, offset=-0.5),
|
||||
:rtriangle => makeshape(3, offset=0.0),
|
||||
:ltriangle => makeshape(3, offset=1.0),
|
||||
:utriangle => makeshape(3),
|
||||
:dtriangle => makeshape(3, offset=0.5),
|
||||
:pentagon => makeshape(5),
|
||||
:hexagon => makeshape(6),
|
||||
:heptagon => makeshape(7),
|
||||
@@ -150,14 +141,12 @@ for n in [4,5,6,7,8]
|
||||
_shapes[Symbol("star$n")] = makestar(n)
|
||||
end
|
||||
|
||||
Shape(k::Symbol) = deepcopy(_shapes[k])
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
|
||||
function center(shape::Shape)
|
||||
x, y = coords(shape)
|
||||
x, y = shape_coords(shape)
|
||||
n = length(x)
|
||||
A, Cx, Cy = 0.0, 0.0, 0.0
|
||||
for i=1:n
|
||||
@@ -174,8 +163,8 @@ function center(shape::Shape)
|
||||
Cx / 6A, Cy / 6A
|
||||
end
|
||||
|
||||
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
sx, sy = coords(shape)
|
||||
function Base.scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
sx, sy = shape_coords(shape)
|
||||
cx, cy = c
|
||||
for i=1:length(sx)
|
||||
sx[i] = (sx[i] - cx) * x + cx
|
||||
@@ -184,13 +173,13 @@ function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
shape
|
||||
end
|
||||
|
||||
function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
function Base.scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
shapecopy = deepcopy(shape)
|
||||
scale!(shapecopy, x, y, c)
|
||||
scale!(shape, x, y, c)
|
||||
end
|
||||
|
||||
function translate!(shape::Shape, x::Real, y::Real = x)
|
||||
sx, sy = coords(shape)
|
||||
sx, sy = shape_coords(shape)
|
||||
for i=1:length(sx)
|
||||
sx[i] += x
|
||||
sy[i] += y
|
||||
@@ -200,7 +189,7 @@ end
|
||||
|
||||
function translate(shape::Shape, x::Real, y::Real = x)
|
||||
shapecopy = deepcopy(shape)
|
||||
translate!(shapecopy, x, y)
|
||||
translate!(shape, x, y)
|
||||
end
|
||||
|
||||
function rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
|
||||
@@ -217,12 +206,11 @@ function rotate(x::Real, y::Real, θ::Real, c = center(shape))
|
||||
end
|
||||
|
||||
function rotate!(shape::Shape, Θ::Real, c = center(shape))
|
||||
x, y = coords(shape)
|
||||
x, y = shape_coords(shape)
|
||||
cx, cy = c
|
||||
for i=1:length(x)
|
||||
xi = rotate_x(x[i], y[i], Θ, cx, cy)
|
||||
yi = rotate_y(x[i], y[i], Θ, cx, cy)
|
||||
x[i], y[i] = xi, yi
|
||||
x[i] = rotate_x(x[i], y[i], Θ, cx, cy)
|
||||
y[i] = rotate_y(x[i], y[i], Θ, cx, cy)
|
||||
end
|
||||
shape
|
||||
end
|
||||
@@ -235,7 +223,7 @@ end
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
type Font
|
||||
immutable Font
|
||||
family::AbstractString
|
||||
pointsize::Int
|
||||
halign::Symbol
|
||||
@@ -248,7 +236,7 @@ end
|
||||
function font(args...)
|
||||
|
||||
# defaults
|
||||
family = "sans-serif"
|
||||
family = "Helvetica"
|
||||
pointsize = 14
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
@@ -292,38 +280,6 @@ function font(args...)
|
||||
Font(family, pointsize, halign, valign, rotation, color)
|
||||
end
|
||||
|
||||
function scalefontsize(k::Symbol, factor::Number)
|
||||
f = default(k)
|
||||
f.pointsize = round(Int, factor * f.pointsize)
|
||||
default(k, f)
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes(factor::Number)
|
||||
|
||||
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
|
||||
"""
|
||||
function scalefontsizes(factor::Number)
|
||||
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
|
||||
scalefontsize(k, factor)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes()
|
||||
|
||||
Resets font sizes to initial default values.
|
||||
"""
|
||||
function scalefontsizes()
|
||||
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
|
||||
f = default(k)
|
||||
if k in keys(_initial_fontsizes)
|
||||
factor = f.pointsize / _initial_fontsizes[k]
|
||||
scalefontsize(k, 1.0/factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
"Wrap a string with font info"
|
||||
immutable PlotText
|
||||
str::AbstractString
|
||||
@@ -337,7 +293,11 @@ function text(str, args...)
|
||||
PlotText(string(str), font(args...))
|
||||
end
|
||||
|
||||
Base.length(t::PlotText) = length(t.str)
|
||||
|
||||
annotations(::Void) = []
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns) = Any[anns]
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
@@ -351,9 +311,9 @@ immutable Stroke
|
||||
end
|
||||
|
||||
function stroke(args...; alpha = nothing)
|
||||
width = 1
|
||||
color = :black
|
||||
style = :solid
|
||||
width = nothing
|
||||
color = nothing
|
||||
style = nothing
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
@@ -387,8 +347,8 @@ immutable Brush
|
||||
end
|
||||
|
||||
function brush(args...; alpha = nothing)
|
||||
size = 1
|
||||
color = :black
|
||||
size = nothing
|
||||
color = nothing
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
@@ -413,122 +373,19 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
type SeriesAnnotations
|
||||
strs::AbstractVector # the labels/names
|
||||
font::Font
|
||||
baseshape::Nullable
|
||||
scalefactor::Tuple
|
||||
end
|
||||
function series_annotations(strs::AbstractVector, args...)
|
||||
fnt = font()
|
||||
shp = Nullable{Any}()
|
||||
scalefactor = (1,1)
|
||||
for arg in args
|
||||
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
|
||||
shp = Nullable(arg)
|
||||
elseif isa(arg, Font)
|
||||
fnt = arg
|
||||
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
||||
shp = _shapes[arg]
|
||||
elseif isa(arg, Number)
|
||||
scalefactor = (arg,arg)
|
||||
elseif is_2tuple(arg)
|
||||
scalefactor = arg
|
||||
else
|
||||
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
# if scalefactor != 1
|
||||
# for s in get(shp)
|
||||
# scale!(s, scalefactor, scalefactor, (0,0))
|
||||
# end
|
||||
# end
|
||||
SeriesAnnotations(strs, fnt, shp, scalefactor)
|
||||
end
|
||||
series_annotations(anns::SeriesAnnotations) = anns
|
||||
series_annotations(::Void) = nothing
|
||||
|
||||
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
anns = series[:series_annotations]
|
||||
# msw,msh = anns.scalefactor
|
||||
# ms = series[:markersize]
|
||||
# msw,msh = if isa(ms, AbstractVector)
|
||||
# 1,1
|
||||
# elseif is_2tuple(ms)
|
||||
# ms
|
||||
# else
|
||||
# ms,ms
|
||||
# end
|
||||
|
||||
# @show msw msh
|
||||
if anns != nothing && !isnull(anns.baseshape)
|
||||
# we use baseshape to overwrite the markershape attribute
|
||||
# with a list of custom shapes for each
|
||||
msw,msh = anns.scalefactor
|
||||
msize = Float64[]
|
||||
shapes = Shape[begin
|
||||
str = _cycle(anns.strs,i)
|
||||
|
||||
# get the width and height of the string (in mm)
|
||||
sw, sh = text_size(str, anns.font.pointsize)
|
||||
|
||||
# how much to scale the base shape?
|
||||
# note: it's a rough assumption that the shape fills the unit box [-1,-1,1,1],
|
||||
# so we scale the length-2 shape by 1/2 the total length
|
||||
scalar = (backend() == PyPlotBackend() ? 1.7 : 1.0)
|
||||
xscale = 0.5to_pixels(sw) * scalar
|
||||
yscale = 0.5to_pixels(sh) * scalar
|
||||
|
||||
# we save the size of the larger direction to the markersize list,
|
||||
# and then re-scale a copy of baseshape to match the w/h ratio
|
||||
maxscale = max(xscale, yscale)
|
||||
push!(msize, maxscale)
|
||||
baseshape = _cycle(get(anns.baseshape),i)
|
||||
shape = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
|
||||
end for i=1:length(anns.strs)]
|
||||
series[:markershape] = shapes
|
||||
series[:markersize] = msize
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
type EachAnn
|
||||
anns
|
||||
x
|
||||
y
|
||||
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
|
||||
else
|
||||
tmp, ea.anns.font
|
||||
end
|
||||
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
|
||||
end
|
||||
|
||||
annotations(::Void) = []
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns) = Any[anns]
|
||||
annotations(sa::SeriesAnnotations) = sa
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"type which represents z-values for colors and sizes (and anything else that might come up)"
|
||||
immutable ZValues
|
||||
values::Vector{Float64}
|
||||
zrange::Tuple{Float64,Float64}
|
||||
end
|
||||
|
||||
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values)))
|
||||
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (minimum(values), maximum(values)))
|
||||
ZValues(collect(float(values)), map(Float64, zrange))
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
abstract type AbstractSurface end
|
||||
abstract AbstractSurface
|
||||
|
||||
"represents a contour or surface mesh"
|
||||
immutable Surface{M<:AMat} <: AbstractSurface
|
||||
@@ -542,7 +399,7 @@ Base.Array(surf::Surface) = surf.surf
|
||||
for f in (:length, :size)
|
||||
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
|
||||
end
|
||||
Base.copy(surf::Surface) = Surface(copy(surf.surf))
|
||||
Base.copy(surf::Surface) = Surface{typeof(surf.surf)}(copy(surf.surf))
|
||||
Base.eltype{T}(surf::Surface{T}) = eltype(T)
|
||||
|
||||
function expand_extrema!(a::Axis, surf::Surface)
|
||||
@@ -558,59 +415,24 @@ immutable SurfaceFunction <: AbstractSurface
|
||||
f::Function
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# # I don't want to clash with ValidatedNumerics, but this would be nice:
|
||||
# ..(a::T, b::T) = (a,b)
|
||||
|
||||
immutable Volume{T}
|
||||
v::Array{T,3}
|
||||
x_extents::Tuple{T,T}
|
||||
y_extents::Tuple{T,T}
|
||||
z_extents::Tuple{T,T}
|
||||
end
|
||||
|
||||
default_extents{T}(::Type{T}) = (zero(T), one(T))
|
||||
|
||||
function Volume{T}(v::Array{T,3},
|
||||
x_extents = default_extents(T),
|
||||
y_extents = default_extents(T),
|
||||
z_extents = default_extents(T))
|
||||
Volume(v, x_extents, y_extents, z_extents)
|
||||
end
|
||||
|
||||
Base.Array(vol::Volume) = vol.v
|
||||
for f in (:length, :size)
|
||||
@eval Base.$f(vol::Volume, args...) = $f(vol.v, args...)
|
||||
end
|
||||
Base.copy{T}(vol::Volume{T}) = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
|
||||
Base.eltype{T}(vol::Volume{T}) = T
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# style is :open or :closed (for now)
|
||||
immutable Arrow
|
||||
style::Symbol
|
||||
side::Symbol # :head (default), :tail, or :both
|
||||
headlength::Float64
|
||||
headwidth::Float64
|
||||
end
|
||||
|
||||
function arrow(args...)
|
||||
style = :simple
|
||||
side = :head
|
||||
headlength = 0.3
|
||||
headwidth = 0.3
|
||||
setlength = false
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
if T == Symbol
|
||||
if arg in (:head, :tail, :both)
|
||||
side = arg
|
||||
else
|
||||
style = arg
|
||||
end
|
||||
style = arg
|
||||
elseif T <: Number
|
||||
# first we apply to both, but if there's more, then only change width after the first number
|
||||
headwidth = Float64(arg)
|
||||
@@ -624,7 +446,7 @@ function arrow(args...)
|
||||
warn("Skipped arrow arg $arg")
|
||||
end
|
||||
end
|
||||
Arrow(style, side, headlength, headwidth)
|
||||
Arrow(style, headlength, headwidth)
|
||||
end
|
||||
|
||||
|
||||
@@ -643,45 +465,58 @@ function add_arrows(func::Function, x::AVec, y::AVec)
|
||||
end
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"Represents data values with formatting that should apply to the tick labels."
|
||||
immutable Formatted{T}
|
||||
data::T
|
||||
formatter::Function
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
type BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
control_points::Vector{T}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
function (bc::BezierCurve)(t::Real)
|
||||
p = zero(P2)
|
||||
n = length(bc.control_points)-1
|
||||
for i in 0:n
|
||||
p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
|
||||
end
|
||||
p
|
||||
@compat function (bc::BezierCurve)(t::Real)
|
||||
p = zero(P2)
|
||||
n = length(bc.control_points)-1
|
||||
for i in 0:n
|
||||
p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
|
||||
end
|
||||
p
|
||||
end
|
||||
|
||||
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
|
||||
# mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
|
||||
Base.mean(x::Real, y::Real) = 0.5*(x+y)
|
||||
Base.mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps)
|
||||
|
||||
@deprecate curve_points coords
|
||||
|
||||
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
|
||||
curve_points(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
|
||||
|
||||
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
|
||||
# may create a loop if necessary. Assumes the view is [0,1]
|
||||
function directed_curve(args...; kw...)
|
||||
error("directed_curve has been moved to PlotRecipes")
|
||||
function directed_curve(p::P2, q::P2; xview = 0:1, yview = 0:1)
|
||||
mn = mean(p, q)
|
||||
diff = q - p
|
||||
|
||||
minx, maxx = minimum(xview), maximum(xview)
|
||||
miny, maxy = minimum(yview), maximum(yview)
|
||||
diffpct = P2(diff[1] / (maxx - minx),
|
||||
diff[2] / (maxy - miny))
|
||||
|
||||
# these points give the initial/final "rise"
|
||||
# vertical_offset = P2(0, (maxy - miny) * max(0.03, min(abs(0.5diffpct[2]), 1.0)))
|
||||
vertical_offset = P2(0, max(0.15, 0.5norm(diff)))
|
||||
upper_control = p + vertical_offset
|
||||
lower_control = q - vertical_offset
|
||||
|
||||
# try to figure out when to loop around vs just connecting straight
|
||||
# TODO: choose loop direction based on sign of p[1]??
|
||||
# x_close_together = abs(diffpct[1]) <= 0.05
|
||||
p_is_higher = diff[2] <= 0
|
||||
inside_control_points = if p_is_higher
|
||||
# add curve points which will create a loop
|
||||
sgn = mn[1] < 0.5 * (maxx + minx) ? -1 : 1
|
||||
inside_offset = P2(0.3 * (maxx - minx), 0)
|
||||
additional_offset = P2(sgn * diff[1], 0) # make it even loopier
|
||||
[upper_control + sgn * (inside_offset + max(0, additional_offset)),
|
||||
lower_control + sgn * (inside_offset + max(0, -additional_offset))]
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
function extrema_plus_buffer(v, buffmult = 0.2)
|
||||
vmin,vmax = ignorenan_extrema(v)
|
||||
vdiff = vmax-vmin
|
||||
buffer = vdiff * buffmult
|
||||
vmin - buffer, vmax + buffer
|
||||
BezierCurve([p, upper_control, inside_control_points..., lower_control, q])
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
abstract type ColorScheme end
|
||||
abstract ColorScheme
|
||||
|
||||
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
const FuncOrFuncs = @compat(Union{Function, AVec{Function}})
|
||||
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
|
||||
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
|
||||
|
||||
|
||||
+14
-41
@@ -40,8 +40,8 @@ PlotExample("Colors",
|
||||
"Access predefined palettes (or build your own with the `colorscheme` method). Line/marker colors are auto-generated from the plot's palette, unless overridden. Set 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-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y-0.5)+4, lab="grad")
|
||||
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=(0,:auto), α=0.6)
|
||||
scatter!(y, zcolor=abs(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs(y-0.5)+4, lab="grad")
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -61,13 +61,13 @@ PlotExample("Global",
|
||||
# "Use the `axis` arguments.",
|
||||
# [
|
||||
# :(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT", xlabel="X", title="TITLE"))
|
||||
# ]),
|
||||
# ]),
|
||||
|
||||
PlotExample("Images",
|
||||
"Plot an image. y-axis is set to flipped",
|
||||
[:(begin
|
||||
import FileIO
|
||||
img = FileIO.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
|
||||
import Images
|
||||
img = Images.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
|
||||
plot(img)
|
||||
end)]
|
||||
),
|
||||
@@ -115,22 +115,20 @@ PlotExample("Line types",
|
||||
PlotExample("Line styles",
|
||||
"",
|
||||
[:(begin
|
||||
styles = filter(s -> s in Plots.supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])
|
||||
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
|
||||
styles = filter(s -> s in supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])'
|
||||
n = length(styles)
|
||||
y = cumsum(randn(20,n),1)
|
||||
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
|
||||
plot(y, line = (5, styles), label = map(string,styles))
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Marker types",
|
||||
"",
|
||||
[:(begin
|
||||
markers = filter(m -> m in Plots.supported_markers(), Plots._shape_keys)
|
||||
markers = reshape(markers, 1, length(markers))
|
||||
markers = filter(m -> m in supported_markers(), Plots._shape_keys)'
|
||||
n = length(markers)
|
||||
x = linspace(0,10,n+2)[2:end-1]
|
||||
y = repmat(reshape(reverse(x),1,:), n, 1)
|
||||
y = repmat(reverse(x)', n, 1)
|
||||
scatter(x, y, m=(8,:auto), lab=map(string,markers), bg=:linen, xlim=(0,10), ylim=(0,10))
|
||||
end)]
|
||||
),
|
||||
@@ -216,7 +214,7 @@ PlotExample("Contours",
|
||||
x = 1:0.5:20
|
||||
y = 1:0.5:10
|
||||
f(x,y) = (3x+y^2)*abs(sin(x)+cos(y))
|
||||
X = repmat(reshape(x,1,:), length(y), 1)
|
||||
X = repmat(x', length(y), 1)
|
||||
Y = repmat(y, 1, length(x))
|
||||
Z = map(f, X, Y)
|
||||
p1 = contour(x, y, f, fill=true)
|
||||
@@ -254,7 +252,7 @@ PlotExample("DataFrames",
|
||||
iris = RDatasets.dataset("datasets", "iris")
|
||||
scatter(iris, :SepalLength, :SepalWidth, group=:Species,
|
||||
title = "My awesome plot", xlabel = "Length", ylabel = "Width",
|
||||
marker = (0.5, [:cross :hex :star7], 12), bg=RGB(.2,.2,.2))
|
||||
marker = (0.5, [:+ :h :star7], 12), bg=RGB(.2,.2,.2))
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -270,7 +268,7 @@ PlotExample("Polar Plots",
|
||||
"",
|
||||
[:(begin
|
||||
Θ = linspace(0,1.5π,100)
|
||||
r = abs.(0.1randn(100)+sin.(3Θ))
|
||||
r = abs(0.1randn(100)+sin(3Θ))
|
||||
plot(Θ, r, proj=:polar, m=2)
|
||||
end)]
|
||||
),
|
||||
@@ -280,7 +278,7 @@ PlotExample("Heatmap, categorical axes, and aspect_ratio",
|
||||
[:(begin
|
||||
xs = [string("x",i) for i=1:10]
|
||||
ys = [string("y",i) for i=1:4]
|
||||
z = float((1:4)*reshape(1:10,1,:))
|
||||
z = float((1:4)*(1:10)')
|
||||
heatmap(xs, ys, z, aspect_ratio=1)
|
||||
end)]
|
||||
),
|
||||
@@ -302,32 +300,7 @@ PlotExample("Boxplot and Violin series recipes",
|
||||
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue))
|
||||
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Animation with subplots",
|
||||
"The `layout` macro can be used to create an animation with subplots.",
|
||||
[:(begin
|
||||
l = @layout([[a; b] c])
|
||||
p = plot(plot([sin,cos],1,leg=false),
|
||||
scatter([atan,cos],1,leg=false),
|
||||
plot(log,1,xlims=(1,10π),ylims=(0,5),leg=false),layout=l)
|
||||
|
||||
anim = Animation()
|
||||
for x = linspace(1,10π,100)
|
||||
plot(push!(p,x,Float64[sin(x),cos(x),atan(x),cos(x),log(x)]))
|
||||
frame(anim)
|
||||
end
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Spy",
|
||||
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`",
|
||||
[:(begin
|
||||
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
|
||||
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
|
||||
plot(spy(a, markershape = :dtriangle), spy(b), markersize = 3, title = ["Unique nonzeros" "Different nonzeros"])
|
||||
end)]
|
||||
),
|
||||
)
|
||||
|
||||
]
|
||||
|
||||
|
||||
+34
-115
@@ -9,10 +9,10 @@ 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.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
|
||||
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
|
||||
@compat Base.:.*(m::Measure, n::Number) = m * n
|
||||
@compat Base.:.*(n::Number, m::Measure) = m * n
|
||||
@compat Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
|
||||
@compat Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
|
||||
Base.zero(::Type{typeof(mm)}) = 0mm
|
||||
Base.one(::Type{typeof(mm)}) = 1mm
|
||||
Base.typemin(::typeof(mm)) = -Inf*mm
|
||||
@@ -20,15 +20,15 @@ Base.typemax(::typeof(mm)) = Inf*mm
|
||||
Base.convert{F<:AbstractFloat}(::Type{F}, l::AbsoluteLength) = convert(F, l.value)
|
||||
|
||||
# TODO: these are unintuitive and may cause tricky bugs
|
||||
# Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
|
||||
# Base.:+(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (1 + m1.value))
|
||||
# Base.:-(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 - m2.value))
|
||||
# Base.:-(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (m1.value - 1))
|
||||
# @compat Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
|
||||
# @compat Base.:+(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (1 + m1.value))
|
||||
# @compat Base.:-(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 - m2.value))
|
||||
# @compat Base.:-(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (m1.value - 1))
|
||||
|
||||
Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
|
||||
Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
|
||||
Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
|
||||
Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)
|
||||
@compat Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
|
||||
@compat Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
|
||||
@compat Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
|
||||
@compat Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)
|
||||
|
||||
|
||||
Base.zero(::Type{typeof(pct)}) = 0pct
|
||||
@@ -44,11 +44,11 @@ right(bbox::BoundingBox) = left(bbox) + width(bbox)
|
||||
bottom(bbox::BoundingBox) = top(bbox) + height(bbox)
|
||||
Base.size(bbox::BoundingBox) = (width(bbox), height(bbox))
|
||||
|
||||
# Base.:*{T,N}(m1::Length{T,N}, m2::Length{T,N}) = Length{T,N}(m1.value * m2.value)
|
||||
# @compat Base.:*{T,N}(m1::Length{T,N}, m2::Length{T,N}) = Length{T,N}(m1.value * m2.value)
|
||||
ispositive(m::Measure) = m.value > 0
|
||||
|
||||
# union together bounding boxes
|
||||
function Base.:+(bb1::BoundingBox, bb2::BoundingBox)
|
||||
@compat function Base.:+(bb1::BoundingBox, bb2::BoundingBox)
|
||||
# empty boxes don't change the union
|
||||
ispositive(width(bb1)) || return bb2
|
||||
ispositive(height(bb1)) || return bb2
|
||||
@@ -96,32 +96,6 @@ function Base.show(io::IO, bbox::BoundingBox)
|
||||
print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}")
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# points combined by x/y, pct, and length
|
||||
type MixedMeasures
|
||||
xy::Float64
|
||||
pct::Float64
|
||||
len::AbsoluteLength
|
||||
end
|
||||
|
||||
function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
|
||||
xy = mix.xy
|
||||
pct = mix.pct
|
||||
if mix.len != 0mm
|
||||
f = (letter == :x ? width : height)
|
||||
totlen = f(plotarea(sp))
|
||||
@show totlen
|
||||
pct += mix.len / totlen
|
||||
end
|
||||
if pct != 0
|
||||
amin, amax = axis_limits(sp[Symbol(letter,:axis)])
|
||||
xy += pct * (amax-amin)
|
||||
end
|
||||
xy
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# AbstractLayout
|
||||
|
||||
@@ -139,11 +113,9 @@ function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
|
||||
orighor = :left
|
||||
origver = :top
|
||||
for oarg in oargs
|
||||
if oarg == :center
|
||||
orighor = origver = oarg
|
||||
elseif oarg in (:left, :right, :hcenter)
|
||||
if oarg in (:left, :right)
|
||||
orighor = oarg
|
||||
elseif oarg in (:top, :bottom, :vcenter)
|
||||
elseif oarg in (:top, :bottom)
|
||||
origver = oarg
|
||||
else
|
||||
warn("Unused origin arg in bbox construction: $oarg")
|
||||
@@ -160,17 +132,13 @@ function bbox(x, y, width, height; h_anchor = :left, v_anchor = :top)
|
||||
height = make_measure_vert(height)
|
||||
left = if h_anchor == :left
|
||||
x
|
||||
elseif h_anchor in (:center, :hcenter)
|
||||
0.5w - 0.5width + x
|
||||
else
|
||||
1w - x - width
|
||||
1w - x - width
|
||||
end
|
||||
top = if v_anchor == :top
|
||||
y
|
||||
elseif v_anchor in (:center, :vcenter)
|
||||
0.5h - 0.5height + y
|
||||
else
|
||||
1h - y - height
|
||||
1h - y - height
|
||||
end
|
||||
BoundingBox(left, top, width, height)
|
||||
end
|
||||
@@ -271,9 +239,7 @@ function GridLayout(dims...;
|
||||
# convert(Vector{Float64}, widths),
|
||||
# convert(Vector{Float64}, heights),
|
||||
KW(kw))
|
||||
for i in eachindex(grid)
|
||||
grid[i] = EmptyLayout(layout)
|
||||
end
|
||||
fill!(grid, EmptyLayout(layout))
|
||||
layout
|
||||
end
|
||||
|
||||
@@ -290,7 +256,7 @@ rightpad(layout::GridLayout) = layout.minpad[3]
|
||||
bottompad(layout::GridLayout) = layout.minpad[4]
|
||||
|
||||
|
||||
# here's how this works... first we recursively "update the minimum padding" (which
|
||||
# here's how this works... first we recursively "update the minimum padding" (which
|
||||
# means to calculate the minimum size needed from the edge of the subplot to plot area)
|
||||
# for the whole layout tree. then we can compute the "padding borders" of this
|
||||
# layout as the biggest padding of the children on the perimeter. then we need to
|
||||
@@ -345,6 +311,7 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
||||
minpad_top = map(toppad, layout.grid)
|
||||
minpad_right = map(rightpad, layout.grid)
|
||||
minpad_bottom = map(bottompad, layout.grid)
|
||||
# @show minpad_left minpad_top minpad_right minpad_bottom
|
||||
|
||||
# get the max horizontal (left and right) padding over columns,
|
||||
# and max vertical (bottom and top) padding over rows
|
||||
@@ -353,6 +320,7 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
||||
pad_top = maximum(minpad_top, 2)
|
||||
pad_right = maximum(minpad_right, 1)
|
||||
pad_bottom = maximum(minpad_bottom, 2)
|
||||
# @show pad_left pad_top pad_right pad_bottom
|
||||
|
||||
# make sure the perimeter match the parent
|
||||
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
|
||||
@@ -363,18 +331,22 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
|
||||
# scale this up to the total padding in each direction
|
||||
total_pad_horizontal = sum(pad_left + pad_right)
|
||||
total_pad_vertical = sum(pad_top + pad_bottom)
|
||||
# @show total_pad_horizontal total_pad_vertical
|
||||
|
||||
# now we can compute the total plot area in each direction
|
||||
total_plotarea_horizontal = width(layout) - total_pad_horizontal
|
||||
total_plotarea_vertical = height(layout) - total_pad_vertical
|
||||
# @show total_plotarea_horizontal total_plotarea_vertical
|
||||
|
||||
# recompute widths/heights
|
||||
layout.widths = recompute_lengths(layout.widths)
|
||||
layout.heights = recompute_lengths(layout.heights)
|
||||
# @show layout.widths layout.heights
|
||||
|
||||
# normalize widths/heights so they sum to 1
|
||||
# denom_w = sum(layout.widths)
|
||||
# denom_h = sum(layout.heights)
|
||||
# @show layout.widths layout.heights denom_w, denom_h
|
||||
|
||||
# we have all the data we need... lets compute the plot areas and set the bounding boxes
|
||||
for r=1:nr, c=1:nc
|
||||
@@ -415,6 +387,7 @@ end
|
||||
function update_inset_bboxes!(plt::Plot)
|
||||
for sp in plt.inset_subplots
|
||||
p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox])
|
||||
# @show bbox(sp.parent) sp[:relative_bbox] p_area
|
||||
plotarea!(sp, p_area)
|
||||
|
||||
bbox!(sp, bbox(
|
||||
@@ -463,7 +436,7 @@ end
|
||||
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.")
|
||||
error("When doing layout, n != n_override. You're probably trying to force existing plots into a layout that doesn't fit them.")
|
||||
end
|
||||
layout, n
|
||||
end
|
||||
@@ -529,12 +502,6 @@ function build_layout(layout::GridLayout, n::Integer)
|
||||
i += 1
|
||||
elseif isa(l, GridLayout)
|
||||
# sub-grid
|
||||
if get(l.attr, :width, :auto) != :auto
|
||||
layout.widths[c] = attr(l,:width)
|
||||
end
|
||||
if get(l.attr, :height, :auto) != :auto
|
||||
layout.heights[r] = attr(l,:height)
|
||||
end
|
||||
l, sps, m = build_layout(l, n-i)
|
||||
append!(subplots, sps)
|
||||
merge!(spmap, m)
|
||||
@@ -571,12 +538,6 @@ function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
|
||||
i += length(plt.subplots)
|
||||
elseif isa(l, GridLayout)
|
||||
# sub-grid
|
||||
if get(l.attr, :width, :auto) != :auto
|
||||
layout.widths[c] = attr(l,:width)
|
||||
end
|
||||
if get(l.attr, :height, :auto) != :auto
|
||||
layout.heights[r] = attr(l,:height)
|
||||
end
|
||||
l, sps, m = build_layout(l, numsp-i, plts)
|
||||
append!(subplots, sps)
|
||||
merge!(spmap, m)
|
||||
@@ -636,7 +597,7 @@ function create_grid(expr::Expr)
|
||||
create_grid_curly(expr)
|
||||
else
|
||||
# if it's something else, just return that (might be an existing layout?)
|
||||
esc(expr)
|
||||
expr
|
||||
end
|
||||
end
|
||||
|
||||
@@ -673,18 +634,13 @@ function create_grid_vcat(expr::Expr)
|
||||
end
|
||||
|
||||
function create_grid_curly(expr::Expr)
|
||||
s = expr.args[1]
|
||||
kw = KW()
|
||||
for (i,arg) in enumerate(expr.args[2:end])
|
||||
add_layout_pct!(kw, arg, i, length(expr.args)-1)
|
||||
end
|
||||
s = expr.args[1]
|
||||
if isa(s, Expr) && s.head == :call && s.args[1] == :grid
|
||||
create_grid(:(grid($(s.args[2:end]...), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto))))))
|
||||
elseif isa(s, Symbol)
|
||||
:(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))
|
||||
else
|
||||
error("Unknown use of curly brackets: $expr")
|
||||
end
|
||||
# @show kw
|
||||
:(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))
|
||||
end
|
||||
|
||||
function create_grid(s::Symbol)
|
||||
@@ -698,42 +654,20 @@ end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# make all reference the same axis extrema/values.
|
||||
# merge subplot lists.
|
||||
# make all reference the same axis extrema/values
|
||||
function link_axes!(axes::Axis...)
|
||||
a1 = axes[1]
|
||||
for i=2:length(axes)
|
||||
a2 = axes[i]
|
||||
expand_extrema!(a1, ignorenan_extrema(a2))
|
||||
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
|
||||
a2[k] = a1[k]
|
||||
end
|
||||
|
||||
# make a2's subplot list refer to a1's and add any missing values
|
||||
sps2 = a2.sps
|
||||
for sp in sps2
|
||||
sp in a1.sps || push!(a1.sps, sp)
|
||||
end
|
||||
a2.sps = a1.sps
|
||||
end
|
||||
end
|
||||
|
||||
# figure out which subplots to link
|
||||
function link_subplots(a::AbstractArray{AbstractLayout}, axissym::Symbol)
|
||||
subplots = []
|
||||
for l in a
|
||||
if isa(l, Subplot)
|
||||
push!(subplots, l)
|
||||
elseif isa(l, GridLayout) && size(l) == (1,1)
|
||||
push!(subplots, l[1,1])
|
||||
end
|
||||
end
|
||||
subplots
|
||||
end
|
||||
|
||||
# for some vector or matrix of layouts, filter only the Subplots and link those axes
|
||||
function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol)
|
||||
subplots = link_subplots(a, axissym)
|
||||
subplots = filter(l -> isa(l, Subplot), a)
|
||||
axes = [sp.attr[axissym] for sp in subplots]
|
||||
if length(axes) > 0
|
||||
link_axes!(axes...)
|
||||
@@ -775,18 +709,3 @@ function link_axes!(layout::GridLayout, link::Symbol)
|
||||
link_axes!(l, link)
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
"Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis."
|
||||
function twinx(sp::Subplot)
|
||||
sp[:right_margin] = max(sp[:right_margin], 30px)
|
||||
plot!(sp.plt, inset = (sp[:subplot_index], bbox(0,0,1,1)))
|
||||
twinsp = sp.plt.subplots[end]
|
||||
twinsp[:yaxis][:mirror] = true
|
||||
twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0)
|
||||
link_axes!(sp[:xaxis], twinsp[:xaxis])
|
||||
twinsp
|
||||
end
|
||||
|
||||
twinx(plt::Plot = current()) = twinx(plt[1])
|
||||
|
||||
+69
-113
@@ -5,7 +5,7 @@ defaultOutputFormat(plt::Plot) = "png"
|
||||
function png(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "png")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/png"), plt)
|
||||
writemime(io, MIME("image/png"), plt)
|
||||
close(io)
|
||||
end
|
||||
png(fn::AbstractString) = png(current(), fn)
|
||||
@@ -13,7 +13,7 @@ png(fn::AbstractString) = png(current(), fn)
|
||||
function svg(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "svg")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("image/svg+xml"), plt)
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
close(io)
|
||||
end
|
||||
svg(fn::AbstractString) = svg(current(), fn)
|
||||
@@ -22,7 +22,7 @@ svg(fn::AbstractString) = svg(current(), fn)
|
||||
function pdf(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "pdf")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/pdf"), plt)
|
||||
writemime(io, MIME("application/pdf"), plt)
|
||||
close(io)
|
||||
end
|
||||
pdf(fn::AbstractString) = pdf(current(), fn)
|
||||
@@ -31,49 +31,30 @@ pdf(fn::AbstractString) = pdf(current(), fn)
|
||||
function ps(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "ps")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/postscript"), plt)
|
||||
writemime(io, MIME("application/postscript"), plt)
|
||||
close(io)
|
||||
end
|
||||
ps(fn::AbstractString) = ps(current(), fn)
|
||||
|
||||
function eps(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "eps")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("image/eps"), plt)
|
||||
close(io)
|
||||
end
|
||||
eps(fn::AbstractString) = eps(current(), fn)
|
||||
|
||||
function tex(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "tex")
|
||||
io = open(fn, "w")
|
||||
show(io, MIME("application/x-tex"), plt)
|
||||
writemime(io, MIME("application/x-tex"), plt)
|
||||
close(io)
|
||||
end
|
||||
tex(fn::AbstractString) = tex(current(), fn)
|
||||
|
||||
function html(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "html")
|
||||
io = open(fn, "w")
|
||||
_use_remote[] = true
|
||||
show(io, MIME("text/html"), plt)
|
||||
_use_remote[] = false
|
||||
close(io)
|
||||
end
|
||||
html(fn::AbstractString) = html(current(), fn)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
const _savemap = Dict(
|
||||
@compat const _savemap = Dict(
|
||||
"png" => png,
|
||||
"svg" => svg,
|
||||
"pdf" => pdf,
|
||||
"ps" => ps,
|
||||
"eps" => eps,
|
||||
"tex" => tex,
|
||||
"html" => html,
|
||||
)
|
||||
|
||||
function getExtension(fn::AbstractString)
|
||||
@@ -122,13 +103,6 @@ savefig(fn::AbstractString) = savefig(current(), fn)
|
||||
|
||||
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
|
||||
|
||||
# IJulia only... inline display
|
||||
function inline(plt::Plot = current())
|
||||
isijulia() || error("inline() is IJulia-only")
|
||||
Main.IJulia.clear_output(true)
|
||||
display(Main.IJulia.InlineDisplay(), plt)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot)
|
||||
prepare_output(plt)
|
||||
_display(plt)
|
||||
@@ -137,13 +111,6 @@ end
|
||||
# override the REPL display to open a gui window
|
||||
Base.display(::Base.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)
|
||||
showval in (:inline,:ijulia) && inline(plt)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
const _mimeformats = Dict(
|
||||
@@ -154,37 +121,34 @@ const _mimeformats = Dict(
|
||||
"application/postscript" => "ps",
|
||||
"image/svg+xml" => "svg",
|
||||
"text/plain" => "txt",
|
||||
"application/x-tex" => "tex",
|
||||
)
|
||||
|
||||
const _best_html_output_type = KW(
|
||||
:pyplot => :png,
|
||||
:unicodeplots => :txt,
|
||||
:glvisualize => :png
|
||||
)
|
||||
|
||||
# a backup for html... passes to svg or png depending on the html_output_format arg
|
||||
function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
function Base.writemime(io::IO, ::MIME"text/html", 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
|
||||
if output_type == :png
|
||||
# info("writing png to html output")
|
||||
print(io, "<img src=\"data:image/png;base64,", base64encode(show, MIME("image/png"), plt), "\" />")
|
||||
print(io, "<img src=\"data:image/png;base64,", base64encode(writemime, MIME("image/png"), plt), "\" />")
|
||||
elseif output_type == :svg
|
||||
# info("writing svg to html output")
|
||||
show(io, MIME("image/svg+xml"), plt)
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
elseif output_type == :txt
|
||||
show(io, MIME("text/plain"), plt)
|
||||
writemime(io, MIME("text/plain"), plt)
|
||||
else
|
||||
error("only png or svg allowed. got: $output_type")
|
||||
end
|
||||
end
|
||||
|
||||
function _show{B}(io::IO, m, plt::Plot{B})
|
||||
# Base.show_backtrace(STDOUT, backtrace())
|
||||
warn("_show is not defined for this backend. m=", string(m))
|
||||
function _writemime(io::IO, m, plt::Plot)
|
||||
warn("_writemime is not defined for this backend. m=", string(m))
|
||||
end
|
||||
function _display(plt::Plot)
|
||||
warn("_display is not defined for this backend.")
|
||||
@@ -192,21 +156,19 @@ end
|
||||
|
||||
# for writing to io streams... first prepare, then callback
|
||||
for mime in keys(_mimeformats)
|
||||
@eval function Base.show{B}(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B})
|
||||
@eval function Base.writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
_writemime(io, m, plt)
|
||||
end
|
||||
end
|
||||
|
||||
closeall() = closeall(backend())
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
|
||||
|
||||
if is_installed("FileIO")
|
||||
@eval import FileIO
|
||||
function _show(io::IO, ::MIME"image/png", plt::Plot)
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::Plot)
|
||||
fn = tempname()
|
||||
|
||||
# first save a pdf file
|
||||
@@ -220,18 +182,22 @@ if is_installed("FileIO")
|
||||
FileIO.save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, readstring(open(pngfn)))
|
||||
write(io, readall(open(pngfn)))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# function html_output_format(fmt)
|
||||
# if fmt == "png"
|
||||
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
# print(io, "<img src=\"data:image/png;base64,", base64(show, MIME("image/png"), plt), "\" />")
|
||||
# @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
|
||||
# print(io, "<img src=\"data:image/png;base64,", base64(writemime, MIME("image/png"), plt), "\" />")
|
||||
# end
|
||||
# elseif fmt == "svg"
|
||||
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
# show(io, MIME("image/svg+xml"), plt)
|
||||
# @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
|
||||
# writemime(io, MIME("image/svg+xml"), plt)
|
||||
# end
|
||||
# else
|
||||
# error("only png or svg allowed. got: $fmt")
|
||||
@@ -244,28 +210,29 @@ end
|
||||
# IJulia
|
||||
# ---------------------------------------------------------
|
||||
|
||||
const _ijulia_output = String["text/html"]
|
||||
const _ijulia_output = Compat.ASCIIString["text/html"]
|
||||
|
||||
using Requires
|
||||
@require IJulia begin
|
||||
if IJulia.inited
|
||||
export set_ijulia_output
|
||||
function setup_ijulia()
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
@eval begin
|
||||
import IJulia
|
||||
export set_ijulia_output
|
||||
function set_ijulia_output(mimestr::AbstractString)
|
||||
# info("Setting IJulia output format to $mimestr")
|
||||
global _ijulia_output
|
||||
_ijulia_output[1] = mimestr
|
||||
end
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
global _ijulia_output
|
||||
Dict{Compat.ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt))
|
||||
end
|
||||
|
||||
function set_ijulia_output(mimestr::AbstractString)
|
||||
# info("Setting IJulia output format to $mimestr")
|
||||
global _ijulia_output
|
||||
_ijulia_output[1] = mimestr
|
||||
# default text/plain passes to html... handles Interact issues
|
||||
function Base.writemime(io::IO, m::MIME"text/plain", plt::Plot)
|
||||
writemime(io, MIME("text/html"), plt)
|
||||
end
|
||||
end
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
global _ijulia_output
|
||||
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
|
||||
end
|
||||
|
||||
# default text/plain passes to html... handles Interact issues
|
||||
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
|
||||
show(io, MIME("text/html"), plt)
|
||||
end
|
||||
|
||||
set_ijulia_output("text/html")
|
||||
end
|
||||
end
|
||||
@@ -273,48 +240,37 @@ end
|
||||
# ---------------------------------------------------------
|
||||
# Atom PlotPane
|
||||
# ---------------------------------------------------------
|
||||
@require Juno begin
|
||||
import Hiccup, Media
|
||||
|
||||
if Juno.isactive()
|
||||
Media.media(Plot, Media.Plot)
|
||||
function setup_atom()
|
||||
# @require Atom begin
|
||||
if isatom() && get(ENV, "PLOTS_USE_ATOM_PLOTPANE", false) in (true, 1, "1", "true", "yes")
|
||||
# @eval import Atom, Media
|
||||
@eval import Atom
|
||||
|
||||
# # connects the render function
|
||||
# for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
|
||||
# Atom.Media.media(Plot{T}, Atom.Media.Plot)
|
||||
# end
|
||||
Atom.Media.media(Plot, Atom.Media.Graphical)
|
||||
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
|
||||
|
||||
_show{B}(io::IO, m::MIME"text/plain", plt::Plot{B}) = print(io, "Plot{$B}()")
|
||||
# Atom.displaysize(::Plot) = (535, 379)
|
||||
# Atom.displaytitle(plt::Plot) = "Plots.jl (backend: $(backend(plt)))"
|
||||
|
||||
function Juno.render(e::Juno.Editor, plt::Plot)
|
||||
Juno.render(e, nothing)
|
||||
# this is like "display"... sends an html div with the plot to the PlotPane
|
||||
function Atom.Media.render(pane::Atom.PlotPane, plt::Plot)
|
||||
@show "here"
|
||||
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||
end
|
||||
|
||||
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]
|
||||
jsize = Juno.plotsize()
|
||||
jsize[1] == 0 && (jsize[1] = 400)
|
||||
jsize[2] == 0 && (jsize[2] = 500)
|
||||
# # force text/plain to output to the PlotPane
|
||||
# function Base.writemime(io::IO, ::MIME"text/plain", plt::Plot)
|
||||
# # writemime(io::IO, MIME("text/html"), plt)
|
||||
# Atom.Media.render(pane)
|
||||
# end
|
||||
|
||||
plt[:size] = jsize
|
||||
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
|
||||
plt[:size] = sz
|
||||
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
|
||||
# function Atom.Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
|
||||
# html = Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
+18
-40
@@ -13,7 +13,7 @@ function _expand_seriestype_array(d::KW, args)
|
||||
delete!(d, :seriestype)
|
||||
RecipeData[begin
|
||||
dc = copy(d)
|
||||
dc[:seriestype] = sts[r:r,:]
|
||||
dc[:seriestype] = sts[r,:]
|
||||
RecipeData(dc, args)
|
||||
end for r=1:size(sts,1)]
|
||||
else
|
||||
@@ -95,7 +95,6 @@ function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeD
|
||||
# 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.d
|
||||
preprocessArgs!(kw)
|
||||
_preprocess_userrecipe(kw)
|
||||
warnOnUnsupported_scales(plt.backend, kw)
|
||||
|
||||
@@ -153,7 +152,7 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
|
||||
if get(kw, :smooth, false)
|
||||
x, y = kw[:x], kw[:y]
|
||||
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
|
||||
sx = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
||||
sx = [minimum(x), maximum(x)]
|
||||
sy = β * sx + α
|
||||
push!(kw_list, merge(copy(kw), KW(
|
||||
:seriestype => :path,
|
||||
@@ -184,7 +183,6 @@ 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.d)
|
||||
if data.d[:seriestype] == st
|
||||
error("Plot recipe $st returned the same seriestype: $(data.d)")
|
||||
end
|
||||
@@ -244,13 +242,12 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
end
|
||||
sp = Subplot(backend(), parent=parent)
|
||||
sp.plt = plt
|
||||
push!(plt.subplots, sp)
|
||||
push!(plt.inset_subplots, sp)
|
||||
sp.attr[:relative_bbox] = bb
|
||||
sp.attr[:subplot_index] = length(plt.subplots)
|
||||
push!(plt.subplots, sp)
|
||||
push!(plt.inset_subplots, sp)
|
||||
end
|
||||
end
|
||||
plt[:inset_subplots] = nothing
|
||||
end
|
||||
|
||||
function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
@@ -262,7 +259,7 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
for kw in kw_list
|
||||
# get the Subplot object to which the series belongs.
|
||||
sps = get(kw, :subplot, :auto)
|
||||
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
|
||||
sp = get_subplot(plt, cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
|
||||
kw[:subplot] = sp
|
||||
|
||||
# extract subplot/axis attributes from kw and add to sp_attr
|
||||
@@ -277,24 +274,13 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
attr[Symbol(letter,k)] = v
|
||||
end
|
||||
end
|
||||
for k in (:scale,), letter in (:x,:y,:z)
|
||||
# Series recipes may need access to this information
|
||||
lk = Symbol(letter,k)
|
||||
if haskey(attr, lk)
|
||||
kw[lk] = attr[lk]
|
||||
end
|
||||
end
|
||||
end
|
||||
sp_attrs[sp] = attr
|
||||
end
|
||||
|
||||
# override subplot/axis args. `sp_attrs` take precendence
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
attr = if !haskey(d, :subplot) || d[:subplot] == idx
|
||||
merge(d, get(sp_attrs, sp, KW()))
|
||||
else
|
||||
get(sp_attrs, sp, KW())
|
||||
end
|
||||
attr = merge(d, get(sp_attrs, sp, KW()))
|
||||
_update_subplot_args(plt, sp, attr, idx, false)
|
||||
end
|
||||
|
||||
@@ -344,17 +330,14 @@ 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!(d, :series_annotations, []))
|
||||
# if isa(series_anns, SeriesAnnotations)
|
||||
# series_anns.x = d[:x]
|
||||
# series_anns.y = d[:y]
|
||||
# elseif length(series_anns) > 0
|
||||
# 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]
|
||||
# end
|
||||
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
||||
anns = annotations(pop!(d, :series_annotations, []))
|
||||
if length(anns) > 0
|
||||
x, y = d[:x], d[:y]
|
||||
nx, ny, na = map(length, (x,y,anns))
|
||||
n = max(nx, ny, na)
|
||||
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
|
||||
end
|
||||
sp.attr[:annotations] = vcat(sp_anns, anns)
|
||||
end
|
||||
|
||||
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||
@@ -364,17 +347,16 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||
expand_extrema!(sp[:xaxis], (0,w))
|
||||
expand_extrema!(sp[:yaxis], (0,h))
|
||||
sp[:yaxis].d[:flip] = true
|
||||
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
|
||||
elseif !(st in (:pie, :histogram, :histogram2d))
|
||||
expand_extrema!(sp, d)
|
||||
end
|
||||
end
|
||||
|
||||
function _add_the_series(plt, sp, d)
|
||||
function _add_the_series(plt, 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)
|
||||
end
|
||||
|
||||
@@ -393,11 +375,11 @@ function _process_seriesrecipe(plt::Plot, d::KW)
|
||||
end
|
||||
|
||||
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
|
||||
if is_seriestype_supported(st)
|
||||
if st in supported_types()
|
||||
sp = _prepare_subplot(plt, d)
|
||||
_prepare_annotations(sp, d)
|
||||
_expand_subplot_extrema(sp, d, st)
|
||||
_add_the_series(plt, sp, d)
|
||||
_add_the_series(plt, d)
|
||||
|
||||
else
|
||||
# get a sub list of series for this seriestype
|
||||
@@ -406,10 +388,6 @@ function _process_seriesrecipe(plt::Plot, d::KW)
|
||||
# assuming there was no error, recursively apply the series recipes
|
||||
for data in datalist
|
||||
if isa(data, RecipeData)
|
||||
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.d)
|
||||
else
|
||||
warn("Unhandled recipe: $(data)")
|
||||
|
||||
+10
-34
@@ -60,7 +60,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
|
||||
# build our plot vector from the args
|
||||
n = length(plts_tail) + 1
|
||||
plts = Array{Plot}(n)
|
||||
plts = Array(Plot, n)
|
||||
plts[1] = plt1
|
||||
for (i,plt) in enumerate(plts_tail)
|
||||
plts[i+1] = plt
|
||||
@@ -89,16 +89,8 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
plt.o = _create_backend_figure(plt)
|
||||
plt.init = true
|
||||
|
||||
series_attr = KW()
|
||||
for (k,v) in d
|
||||
if haskey(_series_defaults, k)
|
||||
series_attr[k] = pop!(d,k)
|
||||
end
|
||||
end
|
||||
|
||||
# create the layout and initialize the subplots
|
||||
plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts))
|
||||
cmdidx = 1
|
||||
for (idx, sp) in enumerate(plt.subplots)
|
||||
_initialize_subplot(plt, sp)
|
||||
serieslist = series_list(sp)
|
||||
@@ -108,11 +100,8 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
sp.plt = plt
|
||||
sp.attr[:subplot_index] = idx
|
||||
for series in serieslist
|
||||
merge!(series.d, series_attr)
|
||||
_add_defaults!(series.d, plt, sp, cmdidx)
|
||||
push!(plt.series_list, series)
|
||||
_series_added(plt, series)
|
||||
cmdidx += 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -126,7 +115,9 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
|
||||
# finish up
|
||||
current(plt)
|
||||
_do_plot_show(plt, get(d, :show, default(:show)))
|
||||
if get(d, :show, default(:show))
|
||||
gui()
|
||||
end
|
||||
plt
|
||||
end
|
||||
|
||||
@@ -157,12 +148,7 @@ end
|
||||
# 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, d::KW, args::Tuple)
|
||||
d[:plot_object] = plt
|
||||
|
||||
if !isempty(args) && !isdefined(Main, :StatPlots) &&
|
||||
first(split(string(typeof(args[1])), ".")) == "DataFrames"
|
||||
warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
|
||||
end
|
||||
# d[:plot_object] = plt
|
||||
|
||||
# --------------------------------
|
||||
# "USER RECIPES"
|
||||
@@ -170,9 +156,6 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
|
||||
kw_list = _process_userrecipes(plt, d, args)
|
||||
|
||||
# info(1)
|
||||
# map(DD, kw_list)
|
||||
|
||||
|
||||
# --------------------------------
|
||||
# "PLOT RECIPES"
|
||||
@@ -189,9 +172,6 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
|
||||
end
|
||||
|
||||
# info(2)
|
||||
# map(DD, kw_list)
|
||||
|
||||
# --------------------------------
|
||||
# Plot/Subplot/Layout setup
|
||||
# --------------------------------
|
||||
@@ -204,10 +184,7 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
# --------------------------------
|
||||
# "SERIES RECIPES"
|
||||
# --------------------------------
|
||||
|
||||
# info(3)
|
||||
# map(DD, kw_list)
|
||||
|
||||
|
||||
for kw in kw_list
|
||||
sp::Subplot = kw[:subplot]
|
||||
# idx = get_subplot_index(plt, sp)
|
||||
@@ -232,10 +209,9 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
current(plt)
|
||||
|
||||
# do we want to force display?
|
||||
# if plt[:show]
|
||||
# gui(plt)
|
||||
# end
|
||||
_do_plot_show(plt, plt[:show])
|
||||
if plt[:show]
|
||||
gui(plt)
|
||||
end
|
||||
|
||||
plt
|
||||
end
|
||||
@@ -266,7 +242,7 @@ function prepare_output(plt::Plot)
|
||||
_update_plot_object(plt)
|
||||
end
|
||||
|
||||
function backend_object(plt::Plot)
|
||||
function prepared_object(plt::Plot)
|
||||
prepare_output(plt)
|
||||
plt.o
|
||||
end
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
const _attribute_defaults = Dict(:Series => _series_defaults,
|
||||
:Subplot => _subplot_defaults,
|
||||
:Plot => _plot_defaults,
|
||||
:Axis => _axis_defaults)
|
||||
|
||||
attrtypes() = join(keys(_attribute_defaults), ", ")
|
||||
attributes(attrtype::Symbol) = sort(collect(keys(_attribute_defaults[attrtype])))
|
||||
|
||||
function lookup_aliases(attrtype, attribute)
|
||||
attribute = Symbol(attribute)
|
||||
attribute = in(attribute, keys(_keyAliases)) ? _keyAliases[attribute] : attribute
|
||||
in(attribute, keys(_attribute_defaults[attrtype])) && return attribute
|
||||
error("There is no attribute named $attribute in $attrtype")
|
||||
end
|
||||
|
||||
function plotattr()
|
||||
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
|
||||
end
|
||||
|
||||
function plotattr(attrtype::Symbol)
|
||||
in(attrtype, keys(_attribute_defaults)) || error("Viable options are $(attrtypes())")
|
||||
println("Defined $attrtype attributes are:\n$(join(attributes(attrtype), ", "))")
|
||||
end
|
||||
|
||||
function plotattr(attribute::AbstractString)
|
||||
attribute = Symbol(attribute)
|
||||
attribute = in(attribute, keys(_keyAliases)) ? _keyAliases[attribute] : attribute
|
||||
for (k, v) in _attribute_defaults
|
||||
if in(attribute, keys(v))
|
||||
return plotattr(k, "$attribute")
|
||||
end
|
||||
end
|
||||
error("There is no attribute named $attribute")
|
||||
end
|
||||
|
||||
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(desc, '.')
|
||||
typedesc = desc[1:first_period_idx-1]
|
||||
desc = strip(desc[first_period_idx+1:end])
|
||||
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("$attribute ", typedesc == "" ? "" : "{$typedesc}", "\n",
|
||||
als == "" ? "" : "$als\n",
|
||||
"\n$desc\n",
|
||||
"$(attrtype) attribute, ", def == "" ? "" : " default: $def")
|
||||
end
|
||||
@@ -1,3 +1,468 @@
|
||||
function _precompile_()
|
||||
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
|
||||
precompile(Plots.py_add_series, (Plots.Plot{Plots.PyPlotBackend}, Plots.Series,))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Function,))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Plots.OHLC, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.LinSpace{Float64},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, DataFrames.DataFrame,))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Int64, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Union{UTF8String, ASCIIString}, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Function, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{ASCIIString, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.FloatRange{Float64},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
|
||||
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 2},))
|
||||
precompile(Plots._add_defaults!, (Base.Dict{Symbol, Any}, Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Int64,))
|
||||
precompile(Plots._before_layout_calcs, (Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots._apply_series_recipe, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._add_defaults!, (Base.Dict{Symbol, Any}, Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Int64,))
|
||||
precompile(Plots._apply_series_recipe, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.setup_ijulia, ())
|
||||
precompile(Plots.call, (Type{Plots.Plot{Plots.UnicodePlotsBackend}}, Plots.UnicodePlotsBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.create_grid_vcat, (Expr,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.update_child_bboxes!, (Plots.GridLayout, Array{Measures.Length{:mm, Float64}, 1},))
|
||||
precompile(Plots.preprocessArgs!, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.call, (Type{Plots.Plot{Plots.PyPlotBackend}}, Plots.PyPlotBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
|
||||
precompile(Plots.fix_xy_lengths!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._update_min_padding!, (Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.warnOnUnsupported_args, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.build_layout, (Plots.GridLayout, Int64,))
|
||||
precompile(Plots.build_layout, (Plots.GridLayout, Int64, Array{Plots.Plot, 1},))
|
||||
precompile(Plots.warnOnUnsupported, (Plots.UnicodePlotsBackend, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.link_axes!, (Plots.GridLayout, Symbol,))
|
||||
precompile(Plots.warnOnUnsupported, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._update_plot_args, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.font, (Int64,))
|
||||
precompile(Plots.recompute_lengths, (Array{Measures.Measure, 1},))
|
||||
precompile(Plots._update_plot_object, (Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.font, (Symbol,))
|
||||
precompile(Plots.create_grid, (Expr,))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Void, Int64,))
|
||||
precompile(Plots.pickDefaultBackend, ())
|
||||
precompile(Plots.default_should_widen, (Plots.Axis,))
|
||||
precompile(Plots.setup_atom, ())
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Symbol, Int64,))
|
||||
precompile(Plots.my_hist_2d, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1}, Int64,))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, ASCIIString, Int64,))
|
||||
precompile(Plots.create_grid_curly, (Expr,))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Bool, Int64,))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Int64, Int64,))
|
||||
precompile(Plots.my_hist, (Array{Any, 1}, Array{Float64, 1}, Int64,))
|
||||
precompile(Plots.getpctrange, (Int64,))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{Symbol, 1},))
|
||||
precompile(Plots.default, (Symbol,))
|
||||
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Symbol, Symbol,))
|
||||
precompile(Plots.pie_labels, (Plots.Subplot{Plots.PyPlotBackend}, Plots.Series,))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Measures.Length{:mm, Float64}, Int64,))
|
||||
precompile(Plots.py_path, (Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots._update_min_padding!, (Plots.GridLayout,))
|
||||
precompile(Plots.warnOnUnsupported_scales, (Plots.UnicodePlotsBackend, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Plots.Font, Int64,))
|
||||
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Tuple{Int64, Int64}, Symbol,))
|
||||
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Array{Any, 1}, Int64,))
|
||||
precompile(Plots.default, (Symbol, Tuple{Int64, Int64},))
|
||||
precompile(Plots.warnOnUnsupported_scales, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.axis_limits, (Plots.Axis, Bool,))
|
||||
precompile(Plots.default, (Symbol, Bool,))
|
||||
precompile(Plots.getColorZ, (Plots.ColorGradient, Float64,))
|
||||
precompile(Plots._update_plot_args, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.call, (Type{Plots.Surface}, Function, Base.FloatRange{Float64}, Base.FloatRange{Float64},))
|
||||
precompile(Plots.font, (Symbol,))
|
||||
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64}, Symbol,))
|
||||
precompile(Plots.call, (Array{Any, 1}, Type{Plots.Subplot}, Plots.UnicodePlotsBackend,))
|
||||
precompile(Plots.extractGroupArgs, (Array{ASCIIString, 1}, Array{Float64, 1},))
|
||||
precompile(Plots._update_subplot_args, (Array{Any, 1}, Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.call, (Array{Any, 1}, Type{Plots.Subplot}, Plots.PyPlotBackend,))
|
||||
precompile(Plots._update_subplot_args, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.extractGroupArgs, (Array{Union{UTF8String, ASCIIString}, 1},))
|
||||
precompile(Plots.bbox_to_pcts, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Bool,))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.py_marker, (Plots.Shape,))
|
||||
precompile(Plots.getindex, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
|
||||
precompile(Plots.getindex, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
|
||||
precompile(Plots.discrete_value!, (Plots.Axis, Array{Union{UTF8String, ASCIIString}, 1},))
|
||||
precompile(Plots.prepare_output, (Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.update_inset_bboxes!, (Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.add_layout_pct!, (Base.Dict{Symbol, Any}, Expr, Int64, Int64,))
|
||||
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, ASCIIString, Symbol,))
|
||||
precompile(Plots.call, (Type{Plots.Shape}, Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 2},))
|
||||
precompile(Plots.call, (Array{Any, 1}, Type{Plots.EmptyLayout}, Plots.RootLayout,))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Function, Function,))
|
||||
precompile(Plots.should_add_to_legend, (Plots.Series,))
|
||||
precompile(Plots.plot, (Array{Any, 1}, DataFrames.DataFrame, Symbol,))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Plots.OHLC, 1},))
|
||||
precompile(Plots.convertToAnyVector, (Array{Float64, 2}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{ASCIIString, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1},))
|
||||
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Symbol,))
|
||||
precompile(Plots.aliasesAndAutopick, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Array{Symbol, 1}, Int64,))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Int64, 1},))
|
||||
precompile(Plots.pie, (Array{Any, 1}, Array{ASCIIString, 1},))
|
||||
precompile(Plots.aliasesAndAutopick, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Array{Any, 1}, Int64,))
|
||||
precompile(Plots.merge_with_base_supported, (Array{Symbol, 1},))
|
||||
precompile(Plots.histogram2d, (Array{Any, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Base.StepRange{Int64, Int64}, Array{Float64, 2},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 1},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.font, ())
|
||||
precompile(Plots.plot, (Array{Any, 1}, Base.FloatRange{Float64}, Array{Float64, 1},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Base.FloatRange{Float64}, Base.FloatRange{Float64},))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Function, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.scatter, (Array{Any, 1}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 1},))
|
||||
precompile(Plots.get_zvalues, (Int64,))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Union{UTF8String, ASCIIString}, 1}, Array{Union{UTF8String, ASCIIString}, 1},))
|
||||
precompile(Plots.histogram, (Array{Any, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.hline!, (Array{Any, 1}, Array{Float64, 2},))
|
||||
precompile(Plots.layout_args, (Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.heatmap, (Array{Any, 1}, Array{Union{UTF8String, ASCIIString}, 1},))
|
||||
precompile(Plots._replace_linewidth, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 2},))
|
||||
precompile(Plots.py_markercolor, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.unzip, (Array{Tuple{Float64, Float64}, 1},))
|
||||
precompile(Plots.link_axes!, (Array{Plots.AbstractLayout, 2}, Symbol,))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1},))
|
||||
precompile(Plots.contour, (Array{Any, 1}, Base.FloatRange{Float64},))
|
||||
precompile(Plots.scatter, (Array{Any, 1}, DataFrames.DataFrame,))
|
||||
precompile(Plots.scatter!, (Array{Any, 1}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.scatter!, (Array{Any, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.getxy, (Plots.Plot{Plots.PyPlotBackend}, Int64,))
|
||||
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 2},))
|
||||
precompile(Plots.get_xy, (Array{Plots.OHLC, 1}, Base.UnitRange{Int64},))
|
||||
precompile(Plots.convertToAnyVector, (Array{Function, 1}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.py_add_annotations, (Plots.Subplot{Plots.PyPlotBackend}, Int64, Float64, Plots.PlotText,))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.get_color_palette, (Symbol, ColorTypes.RGB{Float64}, Int64,))
|
||||
precompile(Plots.py_add_annotations, (Plots.Subplot{Plots.PyPlotBackend}, Float64, Float64, Plots.PlotText,))
|
||||
precompile(Plots.py_colormap, (Plots.ColorGradient, Float64,))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Plots.Stroke,))
|
||||
precompile(Plots.call, (Type{Plots.ColorVector}, Array{Symbol, 1},))
|
||||
precompile(Plots.py_colormap, (Plots.ColorGradient, Void,))
|
||||
precompile(Plots.py_fillcolor, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Float64,))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 2},))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Symbol,))
|
||||
precompile(Plots.call, (Type{Plots.Plot},))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1},))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Array{Int64, 1},))
|
||||
precompile(Plots.getExtension, (UTF8String,))
|
||||
precompile(Plots.call, (Array{Any, 1}, Type{Plots.EmptyLayout},))
|
||||
precompile(Plots.update!, (Array{Any, 1}, Plots.Axis,))
|
||||
precompile(Plots.frame, (Plots.Animation, Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.link_axes!, (Array{Plots.AbstractLayout, 1}, Symbol,))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGB{Float64}, 1},))
|
||||
precompile(Plots.fakedata, (Int64,))
|
||||
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.py_compute_axis_minval, (Plots.Axis,))
|
||||
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.command_idx, (Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.getindex, (Plots.Axis, Symbol,))
|
||||
precompile(Plots.__init__, ())
|
||||
precompile(Plots.isvertical, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.getExtension, (ASCIIString,))
|
||||
precompile(Plots.py_marker, (Symbol,))
|
||||
precompile(Plots.py_init_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64},))
|
||||
precompile(Plots.bucket_index, (Float64, Base.LinSpace{Float64},))
|
||||
precompile(Plots.default, (Array{Any, 1},))
|
||||
precompile(Plots.filter_data!, (Base.Dict{Symbol, Any}, Array{Int64, 1},))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{Symbol, 1}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.slice_arg, (Array{Symbol, 2}, Int64,))
|
||||
precompile(Plots.getindex, (Plots.Plot{Plots.UnicodePlotsBackend}, Symbol,))
|
||||
precompile(Plots.plot!, (Array{Any, 1},))
|
||||
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Float64,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Base.FloatRange{Float64},))
|
||||
precompile(Plots.getindex, (Plots.Plot{Plots.PyPlotBackend}, Symbol,))
|
||||
precompile(Plots.handle_dfs, (DataFrames.DataFrame, Base.Dict{Symbol, Any}, ASCIIString, Symbol,))
|
||||
precompile(Plots.filter_data, (Base.UnitRange{Int64}, Array{Int64, 1},))
|
||||
precompile(Plots.call, (Type{Plots.ColorWrapper}, ColorTypes.RGBA{Float64},))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Array{Symbol, 2},))
|
||||
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Array{Symbol, 2},))
|
||||
precompile(Plots.color_or_nothing!, (Base.Dict{Symbol, Any}, Symbol,))
|
||||
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Plots.Shape,))
|
||||
precompile(Plots.py_fillcolormap, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.transpose_z, (Base.Dict{Symbol, Any}, Array{Float64, 2}, Bool,))
|
||||
precompile(Plots.py_linecolor, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.call, (Type{Plots.OHLC}, Float64, Float64, Float64, Float64,))
|
||||
precompile(Plots.setxy!, (Plots.Plot{Plots.PyPlotBackend}, Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64,))
|
||||
precompile(Plots.push!, (Plots.Segments, Float64, Float64, Float64, Float64,))
|
||||
precompile(Plots.handle_group, (DataFrames.DataFrame, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.lightness_from_background, (ColorTypes.RGB{Float64},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Base.LinSpace{Float64},))
|
||||
precompile(Plots.py_bbox, (Array{Any, 1},))
|
||||
precompile(Plots.py_markerstrokecolor, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.arrow, ())
|
||||
precompile(Plots.convert, (Type{Array{Float64, 1}}, Base.StepRange{Int64, Int64},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Array{Float64, 1},))
|
||||
precompile(Plots.convertLegendValue, (Symbol,))
|
||||
precompile(Plots.slice_arg, (Array{Measures.Length{:mm, Float64}, 2}, Int64,))
|
||||
precompile(Plots.calc_num_subplots, (Plots.GridLayout,))
|
||||
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.slice_arg, (Array{Plots.ColorWrapper, 2}, Int64,))
|
||||
precompile(Plots.slice_arg, (Array{ASCIIString, 2}, Int64,))
|
||||
precompile(Plots.filter_data, (Array{Float64, 1}, Array{Int64, 1},))
|
||||
precompile(Plots.py_linecolormap, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.discrete_value!, (Plots.Axis, ASCIIString,))
|
||||
precompile(Plots.allShapes, (ColorTypes.RGBA{Float64},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Array{Int64, 1},))
|
||||
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.discrete_value!, (Plots.Axis, Symbol,))
|
||||
precompile(Plots.push!, (Plots.Segments, Float64, Int64, Int64, Float64,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Plots.Surface{Array{Float64, 2}},))
|
||||
precompile(Plots.heatmap_edges, (Array{Float64, 1},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Base.StepRange{Int64, Int64},))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Plots.Shape, Symbol,))
|
||||
precompile(Plots.py_color, (Plots.ColorWrapper, Float64,))
|
||||
precompile(Plots.call, (Type{Plots.GridLayout}, Int64, Int64,))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64}, Symbol,))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Bool, Symbol,))
|
||||
precompile(Plots.hvline_limits, (Plots.Axis,))
|
||||
precompile(Plots.current, ())
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Float64, Symbol,))
|
||||
precompile(Plots.compute_gridsize, (Int64, Int64, Int64,))
|
||||
precompile(Plots.py_color, (ColorTypes.RGB{Float64}, Void,))
|
||||
precompile(Plots.interpolate_rgb, (ColorTypes.RGBA{Float64}, ColorTypes.RGBA{Float64}, Float64,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Base.UnitRange{Int64},))
|
||||
precompile(Plots.allShapes, (Float64,))
|
||||
precompile(Plots.warn_on_deprecated_backend, (Symbol,))
|
||||
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Array{Int64, 1},))
|
||||
precompile(Plots.setindex!, (Plots.GridLayout, Plots.EmptyLayout, Int64, Int64,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Tuple{Int64, Int64},))
|
||||
precompile(Plots.allShapes, (Int64,))
|
||||
precompile(Plots.py_markercolormap, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.interpolate_rgb, (ColorTypes.RGB{Float64}, ColorTypes.RGB{Float64}, Float64,))
|
||||
precompile(Plots.get_ticks, (Plots.Axis,))
|
||||
precompile(Plots.backend, ())
|
||||
precompile(Plots.get_xy, (Plots.OHLC{Float64}, Int64, Float64,))
|
||||
precompile(Plots.allShapes, (Plots.Stroke,))
|
||||
precompile(Plots.replaceAliases!, (Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._create_backend_figure, (Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.png, (Plots.Plot{Plots.PyPlotBackend}, UTF8String,))
|
||||
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Symbol,))
|
||||
precompile(Plots.allShapes, (Plots.Shape,))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Plots.Stroke, Symbol,))
|
||||
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Array{Float64, 1},))
|
||||
precompile(Plots.plot, (Array{Float64, 1},))
|
||||
precompile(Plots.rowsize, (Expr,))
|
||||
precompile(Plots.get_axis, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
|
||||
precompile(Plots.png, (Plots.Plot{Plots.PyPlotBackend}, ASCIIString,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Tuple{Float64, Float64},))
|
||||
precompile(Plots._markershape_supported, (Plots.PyPlotBackend, Plots.Shape,))
|
||||
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Bool,))
|
||||
precompile(Plots.supported_types, (Plots.PyPlotBackend,))
|
||||
precompile(Plots.get_axis, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
|
||||
precompile(Plots.setindex!, (Plots.GridLayout, Plots.GridLayout, Int64, Int64,))
|
||||
precompile(Plots.plot, ())
|
||||
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.FloatRange{Float64},))
|
||||
precompile(Plots._markershape_supported, (Plots.PyPlotBackend, Symbol,))
|
||||
precompile(Plots.ok, (Float64, Float64, Int64,))
|
||||
precompile(Plots.allShapes, (Symbol,))
|
||||
precompile(Plots._initialize_backend, (Plots.PyPlotBackend,))
|
||||
precompile(Plots.plot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Plot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.bar, (Array{Float64, 1},))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Int64, Symbol,))
|
||||
precompile(Plots.nanappend!, (Array{Float64, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.autopick, (Array{ColorTypes.RGBA, 1}, Int64,))
|
||||
precompile(Plots.compute_xyz, (Void, Array{Int64, 1}, Void,))
|
||||
precompile(Plots._add_markershape, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots._backend_instance, (Symbol,))
|
||||
precompile(Plots.py_color, (ColorTypes.RGBA{Float64}, Float64,))
|
||||
precompile(Plots.update_child_bboxes!, (Plots.GridLayout,))
|
||||
precompile(Plots._replace_markershape, (Symbol,))
|
||||
precompile(Plots.has_black_border_for_default, (Symbol,))
|
||||
precompile(Plots._filter_input_data!, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.compute_xyz, (Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64},))
|
||||
precompile(Plots.text, (ASCIIString, Int64, Symbol,))
|
||||
precompile(Plots.allShapes, (Array{Symbol, 2},))
|
||||
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.UnitRange{Int64},))
|
||||
precompile(Plots.replaceAlias!, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.compute_xyz, (Array{ASCIIString, 1}, Array{Float64, 1}, Void,))
|
||||
precompile(Plots.layout_args, (Int64,))
|
||||
precompile(Plots.text, (ASCIIString, Symbol, Int64,))
|
||||
precompile(Plots.compute_xyz, (Base.FloatRange{Float64}, Base.FloatRange{Float64}, Plots.Surface{Array{Float64, 2}},))
|
||||
precompile(Plots.all3D, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.cycle, (Array{Plots.Subplot, 1}, Int64,))
|
||||
precompile(Plots.compute_xyz, (Base.StepRange{Int64, Int64}, Array{Float64, 1}, Void,))
|
||||
precompile(Plots.plotarea!, (Plots.Subplot{Plots.PyPlotBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.like_surface, (Symbol,))
|
||||
precompile(Plots.build_layout, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.compute_xyz, (Array{Union{UTF8String, ASCIIString}, 1}, Array{Union{UTF8String, ASCIIString}, 1}, Plots.Surface{Array{Float64, 2}},))
|
||||
precompile(Plots.py_linestyle, (Symbol, Symbol,))
|
||||
precompile(Plots.plot!, (Array{Float64, 2},))
|
||||
precompile(Plots.plot!, (Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 2},))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGB{Float64}, 1}, Base.LinSpace{Float64},))
|
||||
precompile(Plots.py_color, (ColorTypes.RGBA{Float64}, Void,))
|
||||
precompile(Plots.yaxis!, (ASCIIString, Symbol,))
|
||||
precompile(Plots.compute_xyz, (Base.LinSpace{Float64}, Array{Float64, 1}, Void,))
|
||||
precompile(Plots.isijulia, ())
|
||||
precompile(Plots.addExtension, (UTF8String, ASCIIString,))
|
||||
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1}, Array{Float64, 1},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.PyPlotBackend}, Float64, Float64, Float64, Float64,))
|
||||
precompile(Plots.plotarea!, (Plots.GridLayout, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.layout_args, (Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.compute_xyz, (Base.FloatRange{Float64}, Array{Float64, 1}, Void,))
|
||||
precompile(Plots.addExtension, (ASCIIString, ASCIIString,))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Symbol, Symbol,))
|
||||
precompile(Plots._initialize_backend, (Plots.PlotlyBackend,))
|
||||
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Int64, Float64, Float64,))
|
||||
precompile(Plots.bbox!, (Plots.Subplot{Plots.PyPlotBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.vline!, (Array{Int64, 1},))
|
||||
precompile(Plots.supported_markers, (Plots.PyPlotBackend,))
|
||||
precompile(Plots.bbox!, (Plots.GridLayout, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.stroke, (Int64,))
|
||||
precompile(Plots.compute_xyz, (Array{Float64, 1}, Array{Float64, 1}, Void,))
|
||||
precompile(Plots.right, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.extractGroupArgs, (Symbol, DataFrames.DataFrame, Symbol,))
|
||||
precompile(Plots.generate_colorgradient, (ColorTypes.RGB{Float64},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Extrema, Bool,))
|
||||
precompile(Plots.py_colormap, (Plots.ColorWrapper, Void,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Extrema, Float64,))
|
||||
precompile(Plots.contour, (Base.FloatRange{Float64},))
|
||||
precompile(Plots.bottom, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.text, (ASCIIString, Symbol,))
|
||||
precompile(Plots.create_grid, (Symbol,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Bool,))
|
||||
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Array{Symbol, 2}, Symbol,))
|
||||
precompile(Plots.convertToAnyVector, (Void, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.py_dpi_scale, (Plots.Plot{Plots.PyPlotBackend}, Int64,))
|
||||
precompile(Plots.png, (ASCIIString,))
|
||||
precompile(Plots.supported_scales, (Plots.PyPlotBackend,))
|
||||
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64}, Float64,))
|
||||
precompile(Plots.extendSeriesData, (Array{Float64, 1}, Float64,))
|
||||
precompile(Plots.compute_xyz, (Void, Array{Float64, 1}, Void,))
|
||||
precompile(Plots.py_color, (Symbol,))
|
||||
precompile(Plots.expand_extrema!, (Plots.Extrema, Int64,))
|
||||
precompile(Plots.supported_styles, (Plots.PyPlotBackend,))
|
||||
precompile(Plots._initialize_backend, (Plots.UnicodePlotsBackend,))
|
||||
precompile(Plots._initialize_backend, (Plots.GRBackend,))
|
||||
precompile(Plots.is3d, (Symbol,))
|
||||
precompile(Plots.supported_types, (Plots.UnicodePlotsBackend,))
|
||||
precompile(Plots.compute_xyz, (Array{Float64, 1}, Function, Void,))
|
||||
precompile(Plots.py_color, (Symbol, Void,))
|
||||
precompile(Plots.trueOrAllTrue, (Function, Array{Symbol, 2},))
|
||||
precompile(Plots.typemin, (Measures.Length{:mm, Float64},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Float64,))
|
||||
precompile(Plots.get_subplot_index, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
|
||||
precompile(Plots.leftpad, (Plots.GridLayout,))
|
||||
precompile(Plots._update_subplot_args, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots.centers, (Base.LinSpace{Float64},))
|
||||
precompile(Plots.expand_extrema!, (Plots.Axis, Int64,))
|
||||
precompile(Plots.text, (ASCIIString,))
|
||||
precompile(Plots.convertColor, (ColorTypes.RGB{Float64},))
|
||||
precompile(Plots.py_color, (Plots.ColorWrapper, Void,))
|
||||
precompile(Plots.py_color, (Plots.ColorWrapper,))
|
||||
precompile(Plots.trueOrAllTrue, (Function, Int64,))
|
||||
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64},))
|
||||
precompile(Plots.extrema, (Plots.Axis,))
|
||||
precompile(Plots.top, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.convertColor, (Symbol,))
|
||||
precompile(Plots.size, (Plots.Surface{Array{Float64, 2}},))
|
||||
precompile(Plots.isdark, (ColorTypes.RGB{Float64},))
|
||||
precompile(Plots.rowsize, (Symbol,))
|
||||
precompile(Plots.series_list, (Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.convertToAnyVector, (Array{Float64, 1}, Base.Dict{Symbol, Any},))
|
||||
precompile(Plots.update!, (Plots.Axis,))
|
||||
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Float64, Array{Float64, 1},))
|
||||
precompile(Plots.wraptuple, (Bool,))
|
||||
precompile(Plots.call, (Type{Plots.Shape}, Array{Tuple{Float64, Float64}, 1},))
|
||||
precompile(Plots.slice_arg, (Base.StepRange{Int64, Int64}, Int64,))
|
||||
precompile(Plots.sticks_fillfrom, (Void, Int64,))
|
||||
precompile(Plots.left, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
|
||||
precompile(Plots.gr, ())
|
||||
precompile(Plots.leftpad, (Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.supported_markers, ())
|
||||
precompile(Plots.colorscheme, (Symbol,))
|
||||
precompile(Plots.convertColor, (ColorTypes.RGB{Float64}, Void,))
|
||||
precompile(Plots.isscalar, (Int64,))
|
||||
precompile(Plots.wraptuple, (Int64,))
|
||||
precompile(Plots.call, (Type{Plots.Plot}, Plots.UnicodePlotsBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
|
||||
precompile(Plots.supported_styles, ())
|
||||
precompile(Plots.frame, (Plots.Animation,))
|
||||
precompile(Plots.toppad, (Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.link_axes!, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
|
||||
precompile(Plots.convertLegendValue, (Bool,))
|
||||
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64}, Void,))
|
||||
precompile(Plots.plotly, ())
|
||||
precompile(Plots.ispositive, (Measures.Length{:mm, Float64},))
|
||||
precompile(Plots.rightpad, (Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.call, (Type{Plots.GroupBy}, Array{ASCIIString, 1}, Array{Array{Int64, 1}, 1},))
|
||||
precompile(Plots.px2inch, (Int64,))
|
||||
precompile(Plots.slice_arg, (Tuple{Int64, Int64}, Int64,))
|
||||
precompile(Plots.call, (Type{Plots.UnicodePlotsBackend},))
|
||||
precompile(Plots.trueOrAllTrue, (Function, Symbol,))
|
||||
precompile(Plots.bottompad, (Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.annotate!, (Array{Tuple{Int64, Float64, Plots.PlotText}, 1},))
|
||||
precompile(Plots.get_subplot_index, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.call, (Type{Plots.Plot}, Plots.PyPlotBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
|
||||
precompile(Plots.title!, (ASCIIString,))
|
||||
precompile(Plots.slice_arg, (Bool, Int64,))
|
||||
precompile(Plots.wraptuple, (Float64,))
|
||||
precompile(Plots.bottompad, (Plots.GridLayout,))
|
||||
precompile(Plots.py_stepstyle, (Symbol,))
|
||||
precompile(Plots.link_axes!, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
|
||||
precompile(Plots.call, (Type{Plots.GRBackend},))
|
||||
precompile(Plots.unicodeplots, ())
|
||||
precompile(Plots.rightpad, (Plots.GridLayout,))
|
||||
precompile(Plots.call, (Type{Plots.PlotlyBackend},))
|
||||
precompile(Plots.py_color, (ColorTypes.RGBA{Float64},))
|
||||
precompile(Plots.toppad, (Plots.GridLayout,))
|
||||
precompile(Plots.calc_edges, (Array{Float64, 1}, Int64,))
|
||||
precompile(Plots.colorscheme, (ColorTypes.RGBA{Float64},))
|
||||
precompile(Plots.slice_arg, (Int64, Int64,))
|
||||
precompile(Plots.pyplot, ())
|
||||
precompile(Plots._update_subplot_args, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Int64,))
|
||||
precompile(Plots._series_added, (Plots.Plot{Plots.PyPlotBackend}, Plots.Series,))
|
||||
precompile(Plots.get_color_palette, (Array{ColorTypes.RGBA, 1}, ColorTypes.RGB{Float64}, Int64,))
|
||||
precompile(Plots._initialize_subplot, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
|
||||
precompile(Plots.slice_arg, (Void, Int64,))
|
||||
precompile(Plots.cycle, (Int64, Int64,))
|
||||
precompile(Plots._initialize_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.call, (Type{Plots.PyPlotBackend},))
|
||||
precompile(Plots.update_child_bboxes!, (Plots.Subplot{Plots.PyPlotBackend}, Array{Measures.Length{:mm, Float64}, 1},))
|
||||
precompile(Plots.filter_data, (Void, Array{Int64, 1},))
|
||||
precompile(Plots.slice_arg, (Symbol, Int64,))
|
||||
precompile(Plots.slice_arg, (ASCIIString, Int64,))
|
||||
precompile(Plots.layout_args, (Plots.GridLayout,))
|
||||
precompile(Plots.wraptuple, (Tuple{},))
|
||||
precompile(Plots.calc_num_subplots, (Plots.EmptyLayout,))
|
||||
precompile(Plots.wraptuple, (Tuple{Symbol, Float64, Plots.Stroke},))
|
||||
precompile(Plots.wraptuple, (Tuple{ASCIIString, Tuple{Int64, Int64}, Base.StepRange{Int64, Int64}, Symbol},))
|
||||
precompile(Plots.wraptuple, (Tuple{Int64, Symbol, Float64, Array{Symbol, 2}},))
|
||||
precompile(Plots.wraptuple, (Tuple{Int64, Array{Symbol, 2}},))
|
||||
precompile(Plots.wraptuple, (Tuple{ASCIIString, Symbol},))
|
||||
precompile(Plots._replace_markershape, (Array{Symbol, 2},))
|
||||
precompile(Plots.wraptuple, (Tuple{Symbol, Int64},))
|
||||
precompile(Plots.wraptuple, (Tuple{Array{Symbol, 2}, Int64},))
|
||||
precompile(Plots.wraptuple, (Tuple{Int64, Symbol, Symbol},))
|
||||
precompile(Plots.wraptuple, (Tuple{Int64, Float64, Symbol, Plots.Stroke},))
|
||||
precompile(Plots.wraptuple, (Tuple{Float64, Array{Symbol, 2}, Int64},))
|
||||
precompile(Plots.py_color, (ColorTypes.RGB{Float64},))
|
||||
precompile(Plots.wraptuple, (Tuple{Int64, Float64, Symbol},))
|
||||
precompile(Plots.tovec, (Array{Float64, 1},))
|
||||
precompile(Plots.get_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
|
||||
precompile(Plots.eltype, (Plots.Surface{Array{Float64, 2}},))
|
||||
precompile(Plots.nobigs, (Array{Float64, 1},))
|
||||
precompile(Plots.get_subplot, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
|
||||
precompile(Plots.annotations, (Array{Any, 1},))
|
||||
precompile(Plots.wraptuple, (Tuple{Int64, Symbol},))
|
||||
precompile(Plots.colorscheme, (Plots.ColorWrapper,))
|
||||
precompile(Plots.colorscheme, (Plots.ColorGradient,))
|
||||
precompile(Plots.text, (Plots.PlotText,))
|
||||
precompile(Plots._replace_markershape, (Plots.Shape,))
|
||||
precompile(Plots.wraptuple, (Tuple{Array{Symbol, 2}, Int64, Float64, Plots.Stroke},))
|
||||
precompile(Plots.wraptuple, (Tuple{Plots.Shape, Int64, ColorTypes.RGBA{Float64}},))
|
||||
end
|
||||
|
||||
+378
-465
File diff suppressed because it is too large
Load Diff
+44
-136
@@ -6,12 +6,12 @@
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
|
||||
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
|
||||
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
|
||||
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
@@ -20,7 +20,7 @@ convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector{T<:AbstractString}(v::AVec{T}, d::KW) = Any[v], nothing
|
||||
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, d::KW)
|
||||
if all3D(d)
|
||||
@@ -36,14 +36,11 @@ convertToAnyVector(f::Function, d::KW) = Any[f], nothing
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
|
||||
|
||||
# volume
|
||||
convertToAnyVector(v::Volume, d::KW) = Any[v], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
|
||||
|
||||
# # dates
|
||||
# convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
|
||||
# dates
|
||||
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, d::KW)
|
||||
@@ -96,8 +93,8 @@ nobigs(v) = v
|
||||
end
|
||||
|
||||
# not allowed
|
||||
compute_xyz{F<:Function}(x::Void, y::FuncOrFuncs{F}, z) = error("If you want to plot the function `$y`, you need to define the x values!")
|
||||
compute_xyz{F<:Function}(x::Void, y::Void, z::FuncOrFuncs{F}) = error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
|
||||
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
@@ -110,21 +107,7 @@ immutable SliceIt end
|
||||
|
||||
# the catch-all recipes
|
||||
@recipe function f(::Type{SliceIt}, x, y, z)
|
||||
|
||||
# handle data with formatting attached
|
||||
if typeof(x) <: Formatted
|
||||
xformatter := x.formatter
|
||||
x = x.data
|
||||
end
|
||||
if typeof(y) <: Formatted
|
||||
yformatter := y.formatter
|
||||
y = y.data
|
||||
end
|
||||
if typeof(z) <: Formatted
|
||||
zformatter := z.formatter
|
||||
z = z.data
|
||||
end
|
||||
|
||||
# @show "HERE", typeof((x,y,z))
|
||||
xs, _ = convertToAnyVector(x, d)
|
||||
ys, _ = convertToAnyVector(y, d)
|
||||
zs, _ = convertToAnyVector(z, d)
|
||||
@@ -142,19 +125,21 @@ immutable SliceIt end
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
mz = length(zs)
|
||||
if mx > 0 && my > 0 && mz > 0
|
||||
for i in 1:max(mx, my, mz)
|
||||
# add a new series
|
||||
di = copy(d)
|
||||
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
|
||||
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
|
||||
# ret = Any[]
|
||||
for i in 1:max(mx, my, mz)
|
||||
# add a new series
|
||||
di = copy(d)
|
||||
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
|
||||
# @show i, typeof((xi, yi, zi))
|
||||
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
|
||||
# @show i, typeof((di[:x], di[:y], di[:z]))
|
||||
|
||||
# handle fillrange
|
||||
fr = fillranges[mod1(i,mf)]
|
||||
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
|
||||
# handle fillrange
|
||||
fr = fillranges[mod1(i,mf)]
|
||||
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
|
||||
|
||||
push!(series_list, RecipeData(di, ()))
|
||||
end
|
||||
# @show i, di[:x], di[:y], di[:z]
|
||||
push!(series_list, RecipeData(di, ()))
|
||||
end
|
||||
nothing # don't add a series for the main block
|
||||
end
|
||||
@@ -167,38 +152,6 @@ end
|
||||
|
||||
_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(d, v::AbstractArray)
|
||||
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)
|
||||
else
|
||||
v
|
||||
end
|
||||
end
|
||||
|
||||
# # special handling for Surface... need to properly unwrap and re-wrap
|
||||
# function _apply_type_recipe(d, v::Surface)
|
||||
# T = eltype(v.surf)
|
||||
# @show T
|
||||
# if T <: Integer || T <: AbstractFloat
|
||||
# v
|
||||
# else
|
||||
# ret = _apply_type_recipe(d, v.surf)
|
||||
# if typeof(ret) <: Formatted
|
||||
# Formatted(Surface(ret.data), ret.formatter)
|
||||
# else
|
||||
# v
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
# don't do anything for ints or floats
|
||||
_apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
|
||||
|
||||
# handle "type recipes" by converting inputs, and then either re-calling or slicing
|
||||
@recipe function f(x, y, z)
|
||||
did_replace = false
|
||||
@@ -257,52 +210,23 @@ end
|
||||
# # 1 argument
|
||||
# # --------------------------------------------------------------------
|
||||
|
||||
# helper function to ensure relevant attributes are wrapped by Surface
|
||||
function wrap_surfaces(d::KW)
|
||||
if haskey(d, :fill_z)
|
||||
v = d[:fill_z]
|
||||
if !isa(v, Surface)
|
||||
d[:fill_z] = Surface(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@recipe f(n::Integer) = is3d(get(d,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
|
||||
@recipe f(n::Integer) = n, n, n
|
||||
|
||||
# return a surface if this is a 3d plot, otherwise let it be sliced up
|
||||
@recipe function f{T<:Union{Integer,AbstractFloat}}(mat::AMat{T})
|
||||
@recipe function f{T<:Number}(mat::AMat{T})
|
||||
if all3D(d)
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(d)
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
SliceIt, nothing, mat, nothing
|
||||
end
|
||||
end
|
||||
|
||||
# if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface
|
||||
@recipe function f{T<:AbstractMatrix}(fmt::Formatted{T})
|
||||
if all3D(d)
|
||||
mat = fmt.data
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(d)
|
||||
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
|
||||
else
|
||||
SliceIt, nothing, fmt, nothing
|
||||
end
|
||||
end
|
||||
|
||||
# assume this is a Volume, so construct one
|
||||
@recipe function f{T<:Number}(vol::AbstractArray{T,3}, args...)
|
||||
seriestype := :volume
|
||||
SliceIt, nothing, Volume(vol, args...), nothing
|
||||
end
|
||||
|
||||
|
||||
# # images - grays
|
||||
|
||||
@recipe function f{T<:Gray}(mat::AMat{T})
|
||||
if is_seriestype_supported(:image)
|
||||
if nativeImagesSupported()
|
||||
seriestype := :image
|
||||
n, m = size(mat)
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
@@ -317,10 +241,9 @@ end
|
||||
# # images - colors
|
||||
|
||||
@recipe function f{T<:Colorant}(mat::AMat{T})
|
||||
n, m = size(mat)
|
||||
|
||||
if is_seriestype_supported(:image)
|
||||
if nativeImagesSupported()
|
||||
seriestype := :image
|
||||
n, m = size(mat)
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
seriestype := :heatmap
|
||||
@@ -335,34 +258,29 @@ end
|
||||
|
||||
@recipe function f(shape::Shape)
|
||||
seriestype --> :shape
|
||||
coords(shape)
|
||||
shape_coords(shape)
|
||||
end
|
||||
|
||||
@recipe function f(shapes::AVec{Shape})
|
||||
seriestype --> :shape
|
||||
coords(shapes)
|
||||
shape_coords(shapes)
|
||||
end
|
||||
|
||||
@recipe function f(shapes::AMat{Shape})
|
||||
seriestype --> :shape
|
||||
for j in 1:size(shapes,2)
|
||||
@series coords(vec(shapes[:,j]))
|
||||
@series shape_coords(vec(shapes[:,j]))
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# # function without range... use the current range of the x-axis
|
||||
|
||||
|
||||
# function without range... use the current range of the x-axis
|
||||
|
||||
@recipe function f{F<:Function}(f::FuncOrFuncs{F})
|
||||
plt = d[:plot_object]
|
||||
xmin, xmax = try
|
||||
axis_limits(plt[1][:xaxis])
|
||||
catch
|
||||
-5, 5
|
||||
end
|
||||
f, xmin, xmax
|
||||
end
|
||||
# @recipe function f(f::FuncOrFuncs)
|
||||
# plt = d[:plot_object]
|
||||
# f, xmin(plt), xmax(plt)
|
||||
# end
|
||||
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
@@ -373,9 +291,8 @@ end
|
||||
# # if functions come first, just swap the order (not to be confused with parametric functions...
|
||||
# # as there would be more than one function passed in)
|
||||
|
||||
@recipe function f{F<:Function}(f::FuncOrFuncs{F}, x)
|
||||
F2 = typeof(x)
|
||||
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
|
||||
@recipe function f(f::FuncOrFuncs, x)
|
||||
@assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
|
||||
x, f
|
||||
end
|
||||
|
||||
@@ -404,7 +321,6 @@ end
|
||||
# seriestype := :path3d
|
||||
# end
|
||||
# end
|
||||
wrap_surfaces(d)
|
||||
SliceIt, x, y, z
|
||||
end
|
||||
|
||||
@@ -414,7 +330,6 @@ end
|
||||
@recipe function f(x::AVec, y::AVec, zf::Function)
|
||||
# x = X <: Number ? sort(x) : x
|
||||
# y = Y <: Number ? sort(y) : y
|
||||
wrap_surfaces(d)
|
||||
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
||||
end
|
||||
|
||||
@@ -425,7 +340,6 @@ end
|
||||
if !like_surface(get(d, :seriestype, :none))
|
||||
d[:seriestype] = :contour
|
||||
end
|
||||
wrap_surfaces(d)
|
||||
SliceIt, x, y, Surface(z)
|
||||
end
|
||||
|
||||
@@ -437,23 +351,16 @@ end
|
||||
|
||||
#
|
||||
# # special handling... xmin/xmax with parametric function(s)
|
||||
@recipe function f(f::Function, xmin::Number, xmax::Number)
|
||||
xs = adapted_grid(f, (xmin, xmax))
|
||||
xs, f
|
||||
end
|
||||
@recipe function f{F<:Function}(fs::AbstractArray{F}, xmin::Number, xmax::Number)
|
||||
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
|
||||
xs, fs
|
||||
end
|
||||
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
||||
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n)
|
||||
@recipe f(f::FuncOrFuncs, xmin::Number, xmax::Number) = linspace(xmin, xmax, 100), f
|
||||
@recipe f(fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
||||
@recipe f(fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n)
|
||||
|
||||
#
|
||||
# # special handling... 3D parametric function(s)
|
||||
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec)
|
||||
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec)
|
||||
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
|
||||
end
|
||||
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200)
|
||||
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints = 200)
|
||||
fx, fy, fz, linspace(umin, umax, numPoints)
|
||||
end
|
||||
|
||||
@@ -519,3 +426,4 @@ end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+3
-4
@@ -3,7 +3,6 @@
|
||||
function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
|
||||
Subplot{T}(
|
||||
parent,
|
||||
Series[],
|
||||
(20mm, 5mm, 2mm, 10mm),
|
||||
defaultbox,
|
||||
defaultbox,
|
||||
@@ -32,14 +31,14 @@ get_subplot(plt::Plot, k) = plt.spmap[k]
|
||||
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)
|
||||
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots)
|
||||
|
||||
series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
|
||||
function should_add_to_legend(series::Series)
|
||||
series.d[:primary] && series.d[:label] != "" &&
|
||||
!(series.d[:seriestype] in (
|
||||
:hexbin,:bins2d,:histogram2d,:hline,:vline,
|
||||
:hexbin,:histogram2d,:hline,:vline,
|
||||
:contour,:contourf,:contour3d,:surface,:wireframe,
|
||||
:heatmap, :pie, :image
|
||||
))
|
||||
|
||||
+60
-37
@@ -1,42 +1,65 @@
|
||||
|
||||
function theme(s::Symbol; kw...)
|
||||
# reset?
|
||||
if s == :none || s == :default
|
||||
PlotUtils.clibrary(:Plots)
|
||||
PlotUtils.default_cgrad(default = :sequential, sequential = :inferno)
|
||||
default(;
|
||||
bg = :white,
|
||||
bglegend = :match,
|
||||
bginside = :match,
|
||||
bgoutside = :match,
|
||||
fg = :auto,
|
||||
fglegend = :match,
|
||||
fggrid = :match,
|
||||
fgaxis = :match,
|
||||
fgtext = :match,
|
||||
fgborder = :match,
|
||||
fgguide = :match,
|
||||
palette = :auto
|
||||
)
|
||||
return
|
||||
end
|
||||
const _invisible = RGBA(0,0,0,0)
|
||||
|
||||
# update the default gradient and other defaults
|
||||
thm = PlotThemes._themes[s]
|
||||
if thm.gradient != nothing
|
||||
PlotUtils.clibrary(:misc)
|
||||
PlotUtils.default_cgrad(default = :sequential, sequential = PlotThemes.gradient_name(s))
|
||||
end
|
||||
default(;
|
||||
bg = thm.bg_secondary,
|
||||
bginside = thm.bg_primary,
|
||||
fg = thm.lines,
|
||||
fgtext = thm.text,
|
||||
fgguide = thm.text,
|
||||
fglegend = thm.text,
|
||||
palette = thm.palette,
|
||||
kw...
|
||||
const _themes = KW(
|
||||
:default => KW(
|
||||
:bg => :white,
|
||||
:bglegend => :match,
|
||||
:bginside => :match,
|
||||
:bgoutside => :match,
|
||||
:fg => :auto,
|
||||
:fglegend => :match,
|
||||
:fggrid => :match,
|
||||
:fgaxis => :match,
|
||||
:fgtext => :match,
|
||||
:fgborder => :match,
|
||||
:fgguide => :match,
|
||||
)
|
||||
)
|
||||
|
||||
function add_theme(sym::Symbol, theme::KW)
|
||||
_themes[sym] = theme
|
||||
end
|
||||
|
||||
@deprecate set_theme(s) theme(s)
|
||||
# add a new theme, using an existing theme as the base
|
||||
function add_theme(sym::Symbol;
|
||||
base = :default, # start with this theme
|
||||
bg = _themes[base][:bg],
|
||||
bglegend = _themes[base][:bglegend],
|
||||
bginside = _themes[base][:bginside],
|
||||
bgoutside = _themes[base][:bgoutside],
|
||||
fg = _themes[base][:fg],
|
||||
fglegend = _themes[base][:fglegend],
|
||||
fggrid = _themes[base][:fggrid],
|
||||
fgaxis = _themes[base][:fgaxis],
|
||||
fgtext = _themes[base][:fgtext],
|
||||
fgborder = _themes[base][:fgborder],
|
||||
fgguide = _themes[base][:fgguide],
|
||||
kw...)
|
||||
_themes[sym] = merge(KW(
|
||||
:bg => bg,
|
||||
:bglegend => bglegend,
|
||||
:bginside => bginside,
|
||||
:bgoutside => bgoutside,
|
||||
:fg => fg,
|
||||
:fglegend => fglegend,
|
||||
:fggrid => fggrid,
|
||||
:fgaxis => fgaxis,
|
||||
:fgtext => fgtext,
|
||||
:fgborder => fgborder,
|
||||
:fgguide => fgguide,
|
||||
), KW(kw))
|
||||
end
|
||||
|
||||
add_theme(:ggplot2,
|
||||
bglegend = _invisible,
|
||||
bginside = :lightgray,
|
||||
fg = :white,
|
||||
fglegend = _invisible,
|
||||
fgtext = :gray,
|
||||
fgguide = :black
|
||||
)
|
||||
|
||||
function set_theme(sym::Symbol)
|
||||
default(; _themes[sym]...)
|
||||
end
|
||||
|
||||
+17
-25
@@ -2,12 +2,16 @@
|
||||
# TODO: I declare lots of types here because of the lacking ability to do forward declarations in current Julia
|
||||
# I should move these to the relevant files when something like "extern" is implemented
|
||||
|
||||
const AVec = AbstractVector
|
||||
const AMat = AbstractMatrix
|
||||
const KW = Dict{Symbol,Any}
|
||||
typealias AVec AbstractVector
|
||||
typealias AMat AbstractMatrix
|
||||
typealias KW Dict{Symbol,Any}
|
||||
|
||||
immutable PlotsDisplay <: Display end
|
||||
|
||||
abstract AbstractBackend
|
||||
abstract AbstractPlot{T<:AbstractBackend}
|
||||
abstract AbstractLayout
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
immutable InputWrapper{T}
|
||||
@@ -17,21 +21,11 @@ wrap{T}(obj::T) = InputWrapper{T}(obj)
|
||||
Base.isempty(wrapper::InputWrapper) = false
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
type Series
|
||||
d::KW
|
||||
end
|
||||
|
||||
attr(series::Series, k::Symbol) = series.d[k]
|
||||
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# a single subplot
|
||||
type Subplot{T<:AbstractBackend} <: AbstractLayout
|
||||
parent::AbstractLayout
|
||||
series_list::Vector{Series} # arguments for each series
|
||||
minpad::Tuple # leftpad, toppad, rightpad, bottompad
|
||||
bbox::BoundingBox # the canvas area which is available to this subplot
|
||||
plotarea::BoundingBox # the part where the data goes
|
||||
@@ -40,13 +34,11 @@ type Subplot{T<:AbstractBackend} <: AbstractLayout
|
||||
plt # the enclosing Plot object (can't give it a type because of no forward declarations)
|
||||
end
|
||||
|
||||
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
|
||||
type Axis
|
||||
sps::Vector{Subplot}
|
||||
sp::Subplot
|
||||
d::KW
|
||||
end
|
||||
|
||||
@@ -58,10 +50,18 @@ Extrema() = Extrema(Inf, -Inf)
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
const SubplotMap = Dict{Any, Subplot}
|
||||
typealias SubplotMap Dict{Any, Subplot}
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
type Series
|
||||
d::KW
|
||||
end
|
||||
|
||||
attr(series::Series, k::Symbol) = series.d[k]
|
||||
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
type Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||
backend::T # the backend type
|
||||
@@ -86,18 +86,10 @@ end
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
|
||||
Base.length(plt::Plot) = length(plt.subplots)
|
||||
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)
|
||||
Base.size(plt::Plot, i::Integer) = size(plt.layout)[i]
|
||||
Base.ndims(plt::Plot) = 2
|
||||
|
||||
# attr(plt::Plot, k::Symbol) = plt.attr[k]
|
||||
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
|
||||
|
||||
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
|
||||
Base.endof(sp::Subplot) = length(series_list(sp))
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
+50
-148
@@ -3,7 +3,7 @@ calcMidpoints(edges::AbstractVector) = Float64[0.5 * (edges[i] + edges[i+1]) for
|
||||
|
||||
"Make histogram-like bins of data"
|
||||
function binData(data, nbins)
|
||||
lo, hi = ignorenan_extrema(data)
|
||||
lo, hi = extrema(data)
|
||||
edges = collect(linspace(lo, hi, nbins+1))
|
||||
midpoints = calcMidpoints(edges)
|
||||
buckets = Int[max(2, min(searchsortedfirst(edges, x), length(edges)))-1 for x in data]
|
||||
@@ -109,7 +109,7 @@ function regressionXY(x, y)
|
||||
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
|
||||
|
||||
# make a line segment
|
||||
regx = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
||||
regx = [minimum(x), maximum(x)]
|
||||
regy = β * regx + α
|
||||
regx, regy
|
||||
end
|
||||
@@ -131,7 +131,7 @@ function replace_image_with_heatmap{T<:Colorant}(z::Array{T})
|
||||
end
|
||||
|
||||
function imageHack(d::KW)
|
||||
is_seriestype_supported(:heatmap) || error("Neither :image or :heatmap are supported!")
|
||||
:heatmap in supported_types() || error("Neither :image or :heatmap are supported!")
|
||||
d[:seriestype] = :heatmap
|
||||
d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z].surf)
|
||||
end
|
||||
@@ -192,7 +192,7 @@ function iter_segments(args...)
|
||||
end
|
||||
|
||||
# helpers to figure out if there are NaN values in a list of array types
|
||||
anynan(i::Int, args::Tuple) = any(a -> !isfinite(_cycle(a,i)), args)
|
||||
anynan(i::Int, args::Tuple) = any(a -> !isfinite(cycle(a,i)), args)
|
||||
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)
|
||||
|
||||
@@ -228,44 +228,34 @@ function Base.next(itr::SegmentsIterator, nextidx::Int)
|
||||
istart:iend, i
|
||||
end
|
||||
|
||||
# Find minimal type that can contain NaN and x
|
||||
# To allow use of NaN separated segments with categorical x axis
|
||||
|
||||
float_extended_type{T}(x::AbstractArray{T}) = Union{T,Float64}
|
||||
float_extended_type{T<:Real}(x::AbstractArray{T}) = Float64
|
||||
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
nop() = nothing
|
||||
notimpl() = error("This has not been implemented yet")
|
||||
|
||||
isnothing(x::Void) = true
|
||||
isnothing(x) = false
|
||||
Base.cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
|
||||
Base.cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
|
||||
|
||||
_cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
|
||||
_cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
|
||||
Base.cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
||||
Base.cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
||||
Base.cycle(v, idx::Int) = v
|
||||
|
||||
_cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
||||
_cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
||||
_cycle(v, idx::Int) = v
|
||||
Base.cycle(v::AVec, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
|
||||
Base.cycle(v::AMat, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
|
||||
Base.cycle(v, idx::AVec{Int}) = v
|
||||
|
||||
_cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
|
||||
_cycle(v::AMat, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
|
||||
_cycle(v, indices::AVec{Int}) = fill(v, length(indices))
|
||||
|
||||
_cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
|
||||
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
|
||||
Base.cycle(grad::ColorGradient, idx::Int) = cycle(grad.colors, idx)
|
||||
|
||||
makevec(v::AVec) = v
|
||||
makevec{T}(v::T) = T[v]
|
||||
|
||||
"duplicate a single value, or pass the 2-tuple through"
|
||||
maketuple(x::Real) = (x,x)
|
||||
maketuple{T,S}(x::Tuple{T,S}) = x
|
||||
maketuple{T,S}(x::@compat(Tuple{T,S})) = x
|
||||
|
||||
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
|
||||
mapFuncOrFuncs{F<:Function}(fs::AVec{F}, u::AVec) = [map(f, u) for f in fs]
|
||||
mapFuncOrFuncs(fs::AVec{Function}, u::AVec) = [map(f, u) for f in fs]
|
||||
|
||||
unzip{X,Y}(xy::AVec{Tuple{X,Y}}) = [t[1] for t in xy], [t[2] for t in xy]
|
||||
unzip{X,Y,Z}(xyz::AVec{Tuple{X,Y,Z}}) = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
|
||||
@@ -283,16 +273,16 @@ unzip{T}(xyuv::FixedSizeArrays.Vec{4,T}) = T[xyuv[1]], T[xyuv[2]], T[xyuv[
|
||||
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
|
||||
function _expand_limits(lims, x)
|
||||
try
|
||||
e1, e2 = ignorenan_extrema(x)
|
||||
lims[1] = NaNMath.min(lims[1], e1)
|
||||
lims[2] = NaNMath.max(lims[2], e2)
|
||||
e1, e2 = extrema(x)
|
||||
lims[1] = min(lims[1], e1)
|
||||
lims[2] = max(lims[2], e2)
|
||||
# catch err
|
||||
# warn(err)
|
||||
end
|
||||
nothing
|
||||
end
|
||||
|
||||
expand_data(v, n::Integer) = [_cycle(v, i) for i=1:n]
|
||||
expand_data(v, n::Integer) = [cycle(v, i) for i=1:n]
|
||||
|
||||
# if the type exists in a list, replace the first occurence. otherwise add it to the end
|
||||
function addOrReplace(v::AbstractVector, t::DataType, args...; kw...)
|
||||
@@ -324,7 +314,7 @@ function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
|
||||
end
|
||||
end
|
||||
|
||||
createSegments(z) = collect(repmat(reshape(z,1,:),2,1))[2:end]
|
||||
createSegments(z) = collect(repmat(z',2,1))[2:end]
|
||||
|
||||
Base.first(c::Colorant) = c
|
||||
Base.first(x::Symbol) = x
|
||||
@@ -332,44 +322,31 @@ Base.first(x::Symbol) = x
|
||||
|
||||
sortedkeys(d::Dict) = sort(collect(keys(d)))
|
||||
|
||||
|
||||
const _scale_base = Dict{Symbol, Real}(
|
||||
:log10 => 10,
|
||||
:log2 => 2,
|
||||
:ln => e,
|
||||
)
|
||||
|
||||
"create an (n+1) list of the outsides of heatmap rectangles"
|
||||
function heatmap_edges(v::AVec, scale::Symbol = :identity)
|
||||
vmin, vmax = ignorenan_extrema(v)
|
||||
extra_min = extra_max = 0.5 * (vmax-vmin) / (length(v)-1)
|
||||
if scale in _logScales
|
||||
vmin > 0 || error("The axis values must be positive for a $scale scale")
|
||||
while vmin - extra_min <= 0
|
||||
extra_min /= _scale_base[scale]
|
||||
end
|
||||
end
|
||||
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
|
||||
function heatmap_edges(v::AVec)
|
||||
vmin, vmax = extrema(v)
|
||||
extra = 0.5 * (vmax-vmin) / (length(v)-1)
|
||||
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
|
||||
end
|
||||
|
||||
|
||||
function calc_r_extrema(x, y)
|
||||
xmin, xmax = ignorenan_extrema(x)
|
||||
ymin, ymax = ignorenan_extrema(y)
|
||||
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
|
||||
ignorenan_extrema(r)
|
||||
xmin, xmax = extrema(x)
|
||||
ymin, ymax = extrema(y)
|
||||
r = 0.5 * min(xmax - xmin, ymax - ymin)
|
||||
extrema(r)
|
||||
end
|
||||
|
||||
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
||||
rmin, rmax = r_extrema
|
||||
phi, r = x, y
|
||||
r = (r - rmin) / (rmax - rmin)
|
||||
r = 0.5 * (r - rmin) / (rmax - rmin)
|
||||
n = max(length(phi), length(r))
|
||||
x = zeros(n)
|
||||
y = zeros(n)
|
||||
for i in 1:n
|
||||
x[i] = _cycle(r,i) * cos.(_cycle(phi,i))
|
||||
y[i] = _cycle(r,i) * sin.(_cycle(phi,i))
|
||||
x[i] = cycle(r,i) * cos(cycle(phi,i))
|
||||
y[i] = cycle(r,i) * sin(cycle(phi,i))
|
||||
end
|
||||
x, y
|
||||
end
|
||||
@@ -409,12 +386,13 @@ isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
|
||||
isvertical(series::Series) = isvertical(series.d)
|
||||
|
||||
|
||||
# ticksType{T<:Real,S<:Real}(ticks::@compat(Tuple{T,S})) = :limits
|
||||
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
|
||||
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
|
||||
ticksType{T<:AVec,S<:AVec}(ticks::Tuple{T,S}) = :ticks_and_labels
|
||||
ticksType{T<:AVec,S<:AVec}(ticks::@compat(Tuple{T,S})) = :ticks_and_labels
|
||||
ticksType(ticks) = :invalid
|
||||
|
||||
limsType{T<:Real,S<:Real}(lims::Tuple{T,S}) = :limits
|
||||
limsType{T<:Real,S<:Real}(lims::@compat(Tuple{T,S})) = :limits
|
||||
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
|
||||
limsType(lims) = :invalid
|
||||
|
||||
@@ -467,8 +445,7 @@ end
|
||||
# for example: PyPlot sends rows to y, so transpose_on_match should be true
|
||||
function transpose_z(d, z, transpose_on_match::Bool = true)
|
||||
if d[:match_dimensions] == transpose_on_match
|
||||
# z'
|
||||
permutedims(z, [2,1])
|
||||
z'
|
||||
else
|
||||
z
|
||||
end
|
||||
@@ -482,7 +459,7 @@ ok(tup::Tuple) = ok(tup...)
|
||||
# compute one side of a fill range from a ribbon
|
||||
function make_fillrange_side(y, rib)
|
||||
frs = zeros(length(y))
|
||||
for (i, (yi, ri)) in enumerate(zip(y, Base.Iterators.cycle(rib)))
|
||||
for (i, (yi, ri)) in enumerate(zip(y, cycle(rib)))
|
||||
frs[i] = yi + ri
|
||||
end
|
||||
frs
|
||||
@@ -493,28 +470,13 @@ function make_fillrange_from_ribbon(kw::KW)
|
||||
y, rib = kw[:y], kw[:ribbon]
|
||||
rib = wraptuple(rib)
|
||||
rib1, rib2 = -first(rib), last(rib)
|
||||
# kw[:ribbon] = nothing
|
||||
kw[:ribbon] = nothing
|
||||
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
|
||||
end
|
||||
|
||||
function get_sp_lims(sp::Subplot, letter::Symbol)
|
||||
axis_limits(sp[Symbol(letter, :axis)])
|
||||
end
|
||||
xlims(sp::Subplot) = get_sp_lims(sp, :x)
|
||||
ylims(sp::Subplot) = get_sp_lims(sp, :y)
|
||||
zlims(sp::Subplot) = get_sp_lims(sp, :z)
|
||||
xlims(plt::Plot, sp_idx::Int = 1) = xlims(plt[sp_idx])
|
||||
ylims(plt::Plot, sp_idx::Int = 1) = ylims(plt[sp_idx])
|
||||
zlims(plt::Plot, sp_idx::Int = 1) = zlims(plt[sp_idx])
|
||||
xlims(sp_idx::Int = 1) = xlims(current(), sp_idx)
|
||||
ylims(sp_idx::Int = 1) = ylims(current(), sp_idx)
|
||||
zlims(sp_idx::Int = 1) = zlims(current(), sp_idx)
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
makekw(; kw...) = KW(kw)
|
||||
|
||||
wraptuple(x::Tuple) = x
|
||||
wraptuple(x::@compat(Tuple)) = x
|
||||
wraptuple(x) = (x,)
|
||||
|
||||
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
|
||||
@@ -522,7 +484,7 @@ trueOrAllTrue(f::Function, x) = f(x)
|
||||
|
||||
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
allShapes(arg) = trueOrAllTrue(a -> is_marker_supported(get(_markerAliases, a, a)), arg) ||
|
||||
allShapes(arg) = trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg) ||
|
||||
trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
allAlphas(arg) = trueOrAllTrue(a -> (typeof(a) <: Real && a > 0 && a < 1) ||
|
||||
(typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a)))), arg)
|
||||
@@ -658,7 +620,7 @@ end
|
||||
# used in updating an existing series
|
||||
|
||||
extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n)
|
||||
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + ignorenan_maximum(v))
|
||||
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + maximum(v))
|
||||
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
|
||||
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
|
||||
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
|
||||
@@ -684,86 +646,26 @@ function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer)
|
||||
series = plt.series_list[i]
|
||||
series.d[:x], series.d[:y] = xy
|
||||
sp = series.d[:subplot]
|
||||
reset_extrema!(sp)
|
||||
expand_extrema!(sp.attr[:xaxis], xy[1])
|
||||
expand_extrema!(sp.attr[:yaxis], xy[2])
|
||||
_series_updated(plt, series)
|
||||
end
|
||||
function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
|
||||
series = plt.series_list[i]
|
||||
series.d[:x], series.d[:y], series.d[:z] = xyz
|
||||
sp = series.d[:subplot]
|
||||
reset_extrema!(sp)
|
||||
expand_extrema!(sp.attr[:xaxis], xyz[1])
|
||||
expand_extrema!(sp.attr[:yaxis], xyz[2])
|
||||
expand_extrema!(sp.attr[:zaxis], xyz[3])
|
||||
_series_updated(plt, series)
|
||||
end
|
||||
|
||||
function setxyz!{X,Y,Z<:AbstractMatrix}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
|
||||
setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i)
|
||||
end
|
||||
|
||||
|
||||
# -------------------------------------------------------
|
||||
# indexing notation
|
||||
|
||||
# Base.getindex(plt::Plot, i::Integer) = getxy(plt, i)
|
||||
Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = (setxy!(plt, xy, i); plt)
|
||||
Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = (setxyz!(plt, xyz, i); plt)
|
||||
|
||||
# -------------------------------------------------------
|
||||
|
||||
# operate on individual series
|
||||
|
||||
function push_x!(series::Series, xi)
|
||||
push!(series[:x], xi)
|
||||
expand_extrema!(series[:subplot][:xaxis], xi)
|
||||
return
|
||||
end
|
||||
function push_y!(series::Series, yi)
|
||||
push!(series[:y], yi)
|
||||
expand_extrema!(series[:subplot][:yaxis], yi)
|
||||
return
|
||||
end
|
||||
function push_z!(series::Series, zi)
|
||||
push!(series[:z], zi)
|
||||
expand_extrema!(series[:subplot][:zaxis], zi)
|
||||
return
|
||||
end
|
||||
|
||||
function Base.push!(series::Series, yi)
|
||||
x = extendSeriesByOne(series[:x])
|
||||
expand_extrema!(series[:subplot][:xaxis], x[end])
|
||||
series[:x] = x
|
||||
push_y!(series, yi)
|
||||
end
|
||||
Base.push!(series::Series, xi, yi) = (push_x!(series,xi); push_y!(series,yi))
|
||||
Base.push!(series::Series, xi, yi, zi) = (push_x!(series,xi); push_y!(series,yi); push_z!(series,zi))
|
||||
|
||||
# -------------------------------------------------------
|
||||
|
||||
function attr!(series::Series; kw...)
|
||||
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")
|
||||
end
|
||||
end
|
||||
_series_updated(series[:subplot].plt, series)
|
||||
series
|
||||
end
|
||||
|
||||
function attr!(sp::Subplot; kw...)
|
||||
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")
|
||||
end
|
||||
end
|
||||
sp
|
||||
end
|
||||
Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = setxy!(plt, xy, i)
|
||||
Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = setxyz!(plt, xyz, i)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# push/append for one series
|
||||
@@ -884,9 +786,9 @@ mm2px(mm::Real) = float(px / MM_PER_PX)
|
||||
|
||||
|
||||
"Smallest x in plot"
|
||||
xmin(plt::Plot) = ignorenan_minimum([ignorenan_minimum(series.d[:x]) for series in plt.series_list])
|
||||
xmin(plt::Plot) = minimum([minimum(series.d[:x]) for series in plt.series_list])
|
||||
"Largest x in plot"
|
||||
xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series in plt.series_list])
|
||||
xmax(plt::Plot) = maximum([maximum(series.d[:x]) for series in plt.series_list])
|
||||
|
||||
"Extrema of x-values in plot"
|
||||
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
julia 0.4
|
||||
|
||||
RecipesBase
|
||||
PlotUtils
|
||||
StatPlots
|
||||
Reexport
|
||||
Measures
|
||||
Showoff
|
||||
FactCheck
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
GR
|
||||
DataFrames
|
||||
RDatasets
|
||||
VisualRegressionTests
|
||||
UnicodePlots
|
||||
Glob
|
||||
|
||||
+9
-4
@@ -15,7 +15,8 @@ end
|
||||
|
||||
using Plots
|
||||
using StatPlots
|
||||
using Base.Test
|
||||
using FactCheck
|
||||
using Glob
|
||||
|
||||
default(size=(500,300))
|
||||
|
||||
@@ -23,7 +24,7 @@ default(size=(500,300))
|
||||
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
|
||||
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
|
||||
|
||||
const _current_plots_version = v"0.12.1"
|
||||
const _current_plots_version = v"0.8.1"
|
||||
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
@@ -42,7 +43,11 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
|
||||
fn = "ref$idx.png"
|
||||
|
||||
# firgure out version info
|
||||
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
|
||||
G = glob(joinpath(relpath(refdir), "*"))
|
||||
# @show refdir fn G
|
||||
slash = (@windows ? "\\" : "/")
|
||||
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
|
||||
versions = reverse(sort(versions))
|
||||
versions = filter(v -> v <= _current_plots_version, versions)
|
||||
# @show refdir fn versions
|
||||
|
||||
@@ -94,7 +99,7 @@ function image_comparison_facts(pkg::Symbol;
|
||||
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, eps=eps) |> success == true
|
||||
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,11 +5,9 @@ set -ex
|
||||
sudo apt-get -qq update
|
||||
# sudo apt-get install -y wkhtmltopdf
|
||||
|
||||
sudo apt-get install -y xfonts-75dpi xfonts-base
|
||||
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
|
||||
sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb
|
||||
# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
# sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
sudo apt-get install -y xfonts-75dpi
|
||||
wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
wkhtmltoimage http://www.google.com test.png
|
||||
ls
|
||||
|
||||
|
||||
+57
-137
@@ -7,165 +7,85 @@ srand(1234)
|
||||
default(show=false, reuse=true)
|
||||
img_eps = isinteractive() ? 1e-2 : 10e-2
|
||||
|
||||
@testset "GR" begin
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
# facts("Gadfly") do
|
||||
# @fact gadfly() --> Plots.GadflyBackend()
|
||||
# @fact backend() --> Plots.GadflyBackend()
|
||||
#
|
||||
# @fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
|
||||
# @fact plot(Int[1,2,3], rand(3)) --> not(nothing)
|
||||
# @fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
|
||||
# @fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
|
||||
#
|
||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
|
||||
# end
|
||||
|
||||
image_comparison_facts(:gr, eps=img_eps)
|
||||
facts("PyPlot") do
|
||||
@fact pyplot() --> Plots.PyPlotBackend()
|
||||
@fact backend() --> Plots.PyPlotBackend()
|
||||
|
||||
image_comparison_facts(:pyplot, skip=[], eps=img_eps)
|
||||
end
|
||||
|
||||
facts("GR") do
|
||||
@fact gr() --> Plots.GRBackend()
|
||||
@fact backend() --> Plots.GRBackend()
|
||||
|
||||
# @linux_only image_comparison_facts(:gr, skip=[], eps=img_eps)
|
||||
end
|
||||
|
||||
facts("Plotly") do
|
||||
@fact plotly() --> Plots.PlotlyBackend()
|
||||
@fact backend() --> Plots.PlotlyBackend()
|
||||
|
||||
# # until png generation is reliable on OSX, just test on linux
|
||||
# @linux_only image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
|
||||
end
|
||||
|
||||
|
||||
@testset "PyPlot" begin
|
||||
@test pyplot() == Plots.PyPlotBackend()
|
||||
@test backend() == Plots.PyPlotBackend()
|
||||
|
||||
image_comparison_facts(:pyplot, eps=img_eps)
|
||||
end
|
||||
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
# lets just make sure it runs without error
|
||||
@test isa(plot(rand(10)), Plots.Plot) == true
|
||||
end
|
||||
|
||||
# The plotlyjs testimages return a connection error on travis:
|
||||
# connect: connection refused (ECONNREFUSED)
|
||||
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# if is_linux() && isinteractive()
|
||||
# image_comparison_facts(:plotlyjs,
|
||||
# skip=[
|
||||
# 2, # animation (skipped for speed)
|
||||
# 27, # (polar plots) takes very long / not working
|
||||
# 31, # animation (skipped for speed)
|
||||
# ],
|
||||
# eps=img_eps)
|
||||
# end
|
||||
# end
|
||||
|
||||
|
||||
# InspectDR returns that error on travis:
|
||||
# ERROR: LoadError: InitError: Cannot open display:
|
||||
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
|
||||
|
||||
# @testset "InspectDR" begin
|
||||
# @test inspectdr() == Plots.InspectDRBackend()
|
||||
# @test backend() == Plots.InspectDRBackend()
|
||||
#
|
||||
# image_comparison_facts(:inspectdr,
|
||||
# skip=[
|
||||
# 2, # animation
|
||||
# 6, # heatmap not defined
|
||||
# 10, # heatmap not defined
|
||||
# 22, # contour not defined
|
||||
# 23, # pie not defined
|
||||
# 27, # polar plot not working
|
||||
# 28, # heatmap not defined
|
||||
# 31, # animation
|
||||
# ],
|
||||
# eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "Plotly" begin
|
||||
# @test plotly() == Plots.PlotlyBackend()
|
||||
# @test backend() == Plots.PlotlyBackend()
|
||||
#
|
||||
# # # until png generation is reliable on OSX, just test on linux
|
||||
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "Immerse" begin
|
||||
# @test immerse() == Plots.ImmerseBackend()
|
||||
# @test backend() == Plots.ImmerseBackend()
|
||||
# facts("Immerse") do
|
||||
# @fact immerse() --> Plots.ImmerseBackend()
|
||||
# @fact backend() --> Plots.ImmerseBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Gadfly
|
||||
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
# facts("PlotlyJS") do
|
||||
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
|
||||
# @fact backend() --> Plots.PlotlyJSBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Plotly
|
||||
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "Gadfly" begin
|
||||
# @test gadfly() == Plots.GadflyBackend()
|
||||
# @test backend() == Plots.GadflyBackend()
|
||||
#
|
||||
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
|
||||
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
|
||||
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
|
||||
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
|
||||
#
|
||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
|
||||
# end
|
||||
facts("UnicodePlots") do
|
||||
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
|
||||
@fact backend() --> Plots.UnicodePlotsBackend()
|
||||
|
||||
|
||||
|
||||
|
||||
@testset "Axes" begin
|
||||
p = plot()
|
||||
axis = p.subplots[1][:xaxis]
|
||||
@test typeof(axis) == Plots.Axis
|
||||
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
|
||||
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5,1.5)
|
||||
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
|
||||
Plots.discrete_value!(axis, ["x$i" for i=1:5])
|
||||
Plots.discrete_value!(axis, ["x$i" for i=0:2])
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
|
||||
# lets just make sure it runs without error
|
||||
@fact isa(plot(rand(10)), Plot) --> true
|
||||
end
|
||||
|
||||
|
||||
# tests for preprocessing recipes
|
||||
|
||||
# @testset "recipes" begin
|
||||
facts("Axes") do
|
||||
p = plot()
|
||||
axis = p.subplots[1][:xaxis]
|
||||
@fact typeof(axis) --> Axis
|
||||
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
|
||||
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
|
||||
@fact extrema(axis) --> (0.5,1.5)
|
||||
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
|
||||
# user recipe
|
||||
|
||||
# type T end
|
||||
# @recipe function f(::T)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# bg := :yellow
|
||||
# rand(10)
|
||||
# end
|
||||
# plot(T())
|
||||
|
||||
# plot recipe
|
||||
|
||||
# @recipe function f(::Type{Val{:hiplt}},plt::Plot)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# t := :path
|
||||
# bg:=:green
|
||||
# ()
|
||||
# end
|
||||
# plot(rand(10),t=:hiplt)
|
||||
|
||||
# series recipe
|
||||
|
||||
# @recipe function f(::Type{Val{:hi}},x,y,z)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# t := :path
|
||||
# ()
|
||||
# end
|
||||
# plot(rand(10),t=:hiplt)
|
||||
|
||||
# end
|
||||
Plots.discrete_value!(axis, ["x$i" for i=1:5])
|
||||
Plots.discrete_value!(axis, ["x$i" for i=0:2])
|
||||
@fact extrema(axis) --> (0.5, 7.5)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
FactCheck.exitstatus()
|
||||
end # module
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import SnoopCompile
|
||||
# This only needs to be run once (to generate "/tmp/plots_compiles.csv")
|
||||
|
||||
# SnoopCompile.@snoop "/tmp/plots_compiles.csv" begin
|
||||
# include(joinpath(dirname(@__FILE__), "runtests.jl"))
|
||||
# include(Pkg.dir("Plots", "test","runtests.jl"))
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------
|
||||
@@ -32,5 +32,5 @@ blacklist = ["MIME"]
|
||||
pc, discards = SnoopCompile.parcel(data[end:-1:1,2], subst=subst, blacklist=blacklist)
|
||||
SnoopCompile.write("/tmp/precompile", pc)
|
||||
|
||||
pdir = joinpath(dirname(@__FILE__), "..")
|
||||
pdir = Pkg.dir("Plots")
|
||||
run(`cp /tmp/precompile/precompile_Plots.jl $pdir/src/precompile.jl`)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Pkg.add("ImageMagick")
|
||||
Pkg.build("ImageMagick")
|
||||
# Pkg.clone("ImageMagick")
|
||||
# Pkg.build("ImageMagick")
|
||||
|
||||
Pkg.clone("GR")
|
||||
Pkg.build("GR")
|
||||
# Pkg.clone("GR")
|
||||
# Pkg.build("GR")
|
||||
|
||||
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
|
||||
|
||||
@@ -11,12 +11,11 @@ Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
|
||||
Pkg.clone("StatPlots")
|
||||
Pkg.checkout("PlotUtils")
|
||||
|
||||
# Pkg.clone("Blink")
|
||||
# Pkg.clone("https://github.com/JunoLab/Blink.jl.git")
|
||||
# Pkg.build("Blink")
|
||||
# import Blink
|
||||
# Blink.AtomShell.install()
|
||||
# Pkg.add("Rsvg")
|
||||
# Pkg.add("PlotlyJS")
|
||||
# Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")
|
||||
|
||||
# Pkg.checkout("RecipesBase")
|
||||
# Pkg.clone("VisualRegressionTests")
|
||||
@@ -26,6 +25,4 @@ ENV["PYTHON"] = ""
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.build("PyPlot")
|
||||
|
||||
# Pkg.add("InspectDR")
|
||||
|
||||
Pkg.test("Plots"; coverage=false)
|
||||
|
||||
Reference in New Issue
Block a user