Compare commits
346 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 531a38bc39 | |||
| 77fa5454e2 | |||
| 0cd382a1ce | |||
| 9fc0c98722 | |||
| af23074820 | |||
| fdf2d5b20b | |||
| b37f2141a1 | |||
| 5567038cec | |||
| 0327c9101e | |||
| 3d86d5f530 | |||
| 073724a84c | |||
| 6a129bfe92 | |||
| 53a4c36aab | |||
| eb36f4eca0 | |||
| 54838d386d | |||
| 0235821f24 | |||
| efd116ec52 | |||
| ff0f1c5c50 | |||
| 6bbb26d2ea | |||
| 2a1140c0b3 | |||
| a80c7ada27 | |||
| 9bc6d0c7d1 | |||
| f3566a4933 | |||
| cd958a6c68 | |||
| 4f6a920f72 | |||
| b717cf1dc0 | |||
| 33e5a51a28 | |||
| dca5a7ce4d | |||
| bf4dd78a7d | |||
| 489e484117 | |||
| 6e1cc8449b | |||
| bcc2f089be | |||
| 07843c00d3 | |||
| de12915eba | |||
| 4395718e0c | |||
| 913fdf5247 | |||
| 650c1730c9 | |||
| fba1c66499 | |||
| 1c04823877 | |||
| 6c84624d71 | |||
| 69fa9e7b10 | |||
| 350237a774 | |||
| b73ea55bbd | |||
| 9eac6a1db0 | |||
| ea6ab46a13 | |||
| 5f84865365 | |||
| 337a107168 | |||
| a7485cc7f5 | |||
| 8b4edae358 | |||
| b6dca5e9b1 | |||
| 371f0a6a73 | |||
| b777a2d3c8 | |||
| bdfc4636f0 | |||
| 7ba128db71 | |||
| 0f1d8478ce | |||
| 9eae2ad76b | |||
| f43f2956f5 | |||
| 2dc03cc537 | |||
| 233b0d0de2 | |||
| dc9a044141 | |||
| 518fba759f | |||
| 7dfa1ec984 | |||
| da5a538f89 | |||
| a518796736 | |||
| 13111b3779 | |||
| 8412d77067 | |||
| fe0ea168f3 | |||
| af9d97d561 | |||
| 478f5b6e20 | |||
| c89b125b9a | |||
| a981dc71f9 | |||
| 331dd49326 | |||
| b69c37f1bb | |||
| 20ef846c38 | |||
| cd9f00300c | |||
| d6e5b57a08 | |||
| d5e5d81ee2 | |||
| dee24e6f08 | |||
| 9a2a54b885 | |||
| 4c2b01ccb0 | |||
| ddf4136022 | |||
| 4f8fc61689 | |||
| c8a7a050de | |||
| fb04b3d78b | |||
| 0f28b59c5f | |||
| e2795341d9 | |||
| 04c20b84ad | |||
| 04f5d7e411 | |||
| 82877dc53e | |||
| c7eb22021f | |||
| 654fa0426b | |||
| ae6c1c0c66 | |||
| b3f5939689 | |||
| 184404beac | |||
| 456b8258c3 | |||
| a1896d189c | |||
| e47dde9f41 | |||
| 4be19ba6d8 | |||
| 73a2839e34 | |||
| 224472c90a | |||
| d77be82a99 | |||
| 4320c7b9fb | |||
| 2dcf7fb3dd | |||
| cd1913c008 | |||
| 62694e4a93 | |||
| e92fbadc3a | |||
| 17c10bbe68 | |||
| 6c548f025e | |||
| cc15882faf | |||
| 3fd745a5df | |||
| 5e968e0aa8 | |||
| 1e3783b4dc | |||
| c355e02a20 | |||
| e178dca167 | |||
| 8beee23e21 | |||
| a894d377dc | |||
| f41426c85a | |||
| 41877e362a | |||
| de32b02c75 | |||
| e3cba22ab7 | |||
| 25bcc3cbc1 | |||
| ca5310025f | |||
| 5b9561c13e | |||
| d594ac2f00 | |||
| 5157089d87 | |||
| d5b455b1f9 | |||
| 6cb1ed6c92 | |||
| 3d0d52f82a | |||
| be04828d35 | |||
| 5f9aa2edc0 | |||
| a5751895f0 | |||
| 78b0918216 | |||
| 5a7ed24078 | |||
| 509f8f6a95 | |||
| 6f3301e82f | |||
| 80f11ce30b | |||
| 95a6d24111 | |||
| 1fc2c511af | |||
| 3bcaac7051 | |||
| 25afd5c0e7 | |||
| dbbbeddad0 | |||
| c0f274d54b | |||
| 7816e078b5 | |||
| 56bda82529 | |||
| 54adc34348 | |||
| a4ed700338 | |||
| e2d107a70b | |||
| 31f080e4f4 | |||
| 6e4b9af6b1 | |||
| d301d2a06b | |||
| 2bbd4cbb17 | |||
| 5a2d39320f | |||
| 91158b1c20 | |||
| 06115f25ba | |||
| b3b533db94 | |||
| e16125cb50 | |||
| eb0dbac0c1 | |||
| eb1d1876d3 | |||
| f751b1b7ff | |||
| 34f9cfaa02 | |||
| 6dba32bf99 | |||
| 9529246bfb | |||
| 25774ee4c3 | |||
| 1137513236 | |||
| c76855698e | |||
| be8c66adc9 | |||
| be4a374122 | |||
| d76a6d1c38 | |||
| 5945196a4f | |||
| e164ea4b46 | |||
| db3dca1d73 | |||
| eea30fa253 | |||
| b585a0ef61 | |||
| db82f22320 | |||
| 66ce38d948 | |||
| e61d435b00 | |||
| d0a8985800 | |||
| 4c1c092234 | |||
| f02079dafe | |||
| 4be0093a8a | |||
| 130eb778d3 | |||
| be177e0f80 | |||
| 42f54b8df9 | |||
| 4b60b05f75 | |||
| 6afd0f9f82 | |||
| 8288e85c25 | |||
| bb2f4ff16b | |||
| 682ba1f764 | |||
| e0c679f5ee | |||
| a1d0d028b6 | |||
| 7741872578 | |||
| d1dcd536f5 | |||
| 177d380092 | |||
| 33a15f1e93 | |||
| ad2eaf7aef | |||
| 23ae99b97e | |||
| 3c37de152d | |||
| 2dd99d053a | |||
| c60d66d94a | |||
| 6b814b8dca | |||
| 11c71d7a5d | |||
| d90b2e6142 | |||
| 2ab7f3c767 | |||
| a937fa0ef8 | |||
| bc36749f6d | |||
| 88d1735380 | |||
| 92672ffddf | |||
| 2ccfa9b4fa | |||
| 1f07be6ae0 | |||
| 9a8c7b290f | |||
| 2e3bc15d2b | |||
| 9f0117d914 | |||
| 5e5412887c | |||
| b2efd5150b | |||
| 50ec31a7a3 | |||
| 20bd9d6160 | |||
| 8c3c07acb7 | |||
| 26a56c3105 | |||
| d0070c72fd | |||
| 780f3c49e9 | |||
| 2c191dbdbf | |||
| 4b617f96a3 | |||
| dabc3f998b | |||
| 23a22102c5 | |||
| 8d9ff7af11 | |||
| fdcb6086d1 | |||
| 00e05efd7c | |||
| 0dd5eef3f2 | |||
| 6ecd30d42b | |||
| 317091639f | |||
| 9c8e879465 | |||
| dc5a04346a | |||
| 44b533f501 | |||
| 0fa459d590 | |||
| 96d34bb5ee | |||
| 9f712b44f3 | |||
| 1ff8663e44 | |||
| 52f042263b | |||
| da7e57989c | |||
| 65c3d90642 | |||
| 3c044d729d | |||
| 82ecf894c0 | |||
| 7b15f7d74b | |||
| 371406845c | |||
| ccd26a6d42 | |||
| e992930ff6 | |||
| f66d8bed8f | |||
| 155634ef34 | |||
| dbc7bc4253 | |||
| fc427e618a | |||
| 6d66190644 | |||
| 9b2da0d645 | |||
| 95c60b9554 | |||
| bc7f6a6fac | |||
| 0b1118540a | |||
| 96bd0bb46c | |||
| 33e97ee49b | |||
| 8414facde2 | |||
| 2a0d5a0a03 | |||
| aec30301a1 | |||
| 9cf246a03e | |||
| c385035ac5 | |||
| 409cf2c630 | |||
| 02ddbc8381 | |||
| 1c2a588864 | |||
| de043eeaa2 | |||
| 5e5f23b5e5 | |||
| d671ccd6ba | |||
| f4f2f09d17 | |||
| 2f1c70e49f | |||
| d9890498d1 | |||
| 46ae505bab | |||
| b0e84a68d0 | |||
| 356a5b6136 | |||
| e86193cebe | |||
| e35b2ec3ff | |||
| 69d421d785 | |||
| 47c51b28c1 | |||
| dd2653968e | |||
| b091d95eb2 | |||
| 33327d3992 | |||
| 027ce58655 | |||
| cd611ef4bf | |||
| bc7f5118ea | |||
| 53ae915044 | |||
| a47f14ec13 | |||
| 86149ba3a7 | |||
| cc3822b222 | |||
| 57b9602b13 | |||
| c9839dbefa | |||
| 5b6423ec6c | |||
| b3efcf9b68 | |||
| cadb0f96e2 | |||
| d3b825b49f | |||
| c808cbb4fa | |||
| 228d3af1fa | |||
| a1df325051 | |||
| 8e6fdfac3c | |||
| 9a1afb2376 | |||
| e9ab8c4dac | |||
| 1d98acc407 | |||
| 034613b50c | |||
| 282e611ef7 | |||
| 49fc903334 | |||
| 44b6157f17 | |||
| 0a8d3f9251 | |||
| ac505ede44 | |||
| 4770f8b580 | |||
| 67e5598d28 | |||
| 554d7ab887 | |||
| 40734bf90e | |||
| 3e720f8bae | |||
| 66d9c79bef | |||
| 89a5e5d57a | |||
| 8f6b0c50d6 | |||
| d85dfaf38a | |||
| 8511152982 | |||
| 40f9a51d4f | |||
| 30ad6d93bc | |||
| 770d907fb8 | |||
| 46cdbacf0b | |||
| c0a8adc167 | |||
| 4dd176a7f2 | |||
| eac9023b9a | |||
| a4c403286d | |||
| 3a2ee0fc72 | |||
| f097fb57b5 | |||
| 7415a362c4 | |||
| 8a7b7f5c9b | |||
| 4ce35ef352 | |||
| a12f601b9c | |||
| 4106161aa8 | |||
| 58c2f35bcf | |||
| c41839a816 | |||
| c7a13a4641 | |||
| dd526e00ab | |||
| bad2ef63c6 | |||
| 6cca763284 | |||
| 915c41c9d9 | |||
| 9c2c548874 | |||
| fdf699bf35 | |||
| e3ce1ab1d1 | |||
| af56d6f265 | |||
| 93d16a27c1 | |||
| a602309a02 | |||
| 11e9eb3aa3 |
+1
-1
@@ -4,7 +4,7 @@ os:
|
||||
- linux
|
||||
# - osx
|
||||
julia:
|
||||
- 0.5
|
||||
- 0.6
|
||||
matrix:
|
||||
allow_failures:
|
||||
- julia: nightly
|
||||
|
||||
@@ -3,14 +3,92 @@
|
||||
|
||||
#### notes on release changes, ongoing development, and future planned work
|
||||
|
||||
- All new development should target 0.12!
|
||||
- All new development should target 0.13!
|
||||
- Minor version 0.11 is the last one to support Julia 0.5!!
|
||||
- Critical bugfixes only
|
||||
- `backports` branch is for Julia 0.4
|
||||
- `backports` branch is for Julia 0.5
|
||||
|
||||
---
|
||||
## (current master)
|
||||
|
||||
## 0.11 (current master/dev)
|
||||
## 0.13.1
|
||||
|
||||
- fix a bug when passing a vector of functions with no bounds (e.g. `plot([sin, cos])`)
|
||||
- export `pct` and `px` from Plots.PlotMeasures
|
||||
|
||||
## 0.13.0
|
||||
|
||||
- support `plotattributes` rather than `d` in recipes
|
||||
- no longer export `w`, `h` and names from Measures.jl; use `using Plots.PlotMeasures` to get these names back
|
||||
- `bar_width` now depends on the minimum distance between bars, not the mean
|
||||
- better automatic x axis limits for plotting Functions
|
||||
- `tick_direction` attribute now allows ticks to be on the inside of the plot border
|
||||
- removed a bug where `p1 = plot(randn(10)); plot(p1, p2)` made `display(p1)` impossible
|
||||
- allow `plot([])` to generate an empty plot
|
||||
- add `origin` framestyle
|
||||
- ensure finite bin number on histograms with only one unique value
|
||||
- better automatic histogram bins for 2d histograms
|
||||
- more informative error message on passing unsupported seriestype in a recipe
|
||||
- allow grouping in user recipes
|
||||
- GR now has `line_z` and `fill_z` attributes for determining the color of shapes and lines
|
||||
- change GR default view angle for 3D plots to match that of PyPlot
|
||||
- fix `clims` on GR
|
||||
- fix `marker_z` for plotly backend
|
||||
- implement `framestyle` for plotly
|
||||
- fix logscale bug error for values < 1e-16 on pyplot
|
||||
- fix an issue on pyplot where >1 colorbar would be shown if there was >1 series
|
||||
- fix `writemime` for eps
|
||||
|
||||
## 0.12.4
|
||||
|
||||
- added a new `framestyle` argument with choices: :box, :semi, :axes, :grid and :none
|
||||
- changed the default bar width to 0.8
|
||||
- added working ribbon to plotly backend
|
||||
- ensure that automatic ticks always generate 4 to 8 ticks
|
||||
- group now groups keyword arguments of the same length as the input
|
||||
- allow passing DateTime objects as ticks
|
||||
- allow specifying the number of ticks as an integre
|
||||
- fix bug on errorbars in gr
|
||||
- fixed some but not all world age issues
|
||||
- better margin with room for text
|
||||
- added a `match` option for linecolor
|
||||
- better error message un unsupported series types
|
||||
- add a 'stride' keyword for the pyplot backend
|
||||
|
||||
## 0.12.3
|
||||
|
||||
- new grid line style defaults
|
||||
- `grid` is now an axis attribute and a magic argument: it is now possible to modify the grid line style, alpha and line width
|
||||
- Enforce plot order in user recipes
|
||||
- import `plot!` from RecipesBase
|
||||
- GR no longer automatically handles _ and ^ in texts
|
||||
- fix GR colorbar for scatter plots
|
||||
|
||||
#### 0.12.2
|
||||
|
||||
- fix an issue with Juno/PlotlyJS compatibility on new installations
|
||||
- fix markers not showing up in seriesrecipes using :scatter
|
||||
- don't use pywrap in the pyplot backend
|
||||
- improve the bottom margin for the gr backend
|
||||
|
||||
#### 0.12.1
|
||||
|
||||
- fix deprecation warnings
|
||||
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
|
||||
- drop FactCheck in tests
|
||||
- remove julia 0.5 compliant uses of transpose operator
|
||||
- fix GR heatmap bugs
|
||||
- fix GR guide padding
|
||||
- improve legend markers in GR
|
||||
- add surface alpha for Plotly(JS)
|
||||
- add fillrange to Plotly(JS)
|
||||
- allow usage of Matplotlib 1.5 with PyPlot
|
||||
- fix GLVisualize for julia 0.6
|
||||
- conform to changes in InspectDR
|
||||
|
||||
#### 0.12.0
|
||||
|
||||
- 0.6 only
|
||||
|
||||
#### 0.11.3
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Plots
|
||||
|
||||
[](https://travis-ci.org/JuliaPlots/Plots.jl)
|
||||
[](https://ci.appveyor.com/project/tbreloff/plots-jl)
|
||||
[](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
|
||||
<!-- [](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
julia 0.5
|
||||
julia 0.6
|
||||
|
||||
RecipesBase
|
||||
RecipesBase 0.2.3
|
||||
PlotUtils 0.4.1
|
||||
PlotThemes 0.1.3
|
||||
Reexport
|
||||
FixedSizeArrays
|
||||
StaticArrays 0.5
|
||||
FixedPointNumbers 0.3
|
||||
Measures
|
||||
Showoff
|
||||
StatsBase 0.14.0
|
||||
JSON
|
||||
NaNMath
|
||||
Requires
|
||||
Contour
|
||||
|
||||
+8
-2
@@ -1,7 +1,13 @@
|
||||
environment:
|
||||
matrix:
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" #check and address
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
|
||||
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
|
||||
|
||||
|
||||
+75
-30
@@ -3,8 +3,12 @@ __precompile__(false)
|
||||
module Plots
|
||||
|
||||
using Reexport
|
||||
using FixedSizeArrays
|
||||
|
||||
import StaticArrays
|
||||
using StaticArrays.FixedSizeArrays
|
||||
|
||||
@reexport using RecipesBase
|
||||
import RecipesBase: plot, plot!, animate
|
||||
using Base.Meta
|
||||
@reexport using PlotUtils
|
||||
@reexport using PlotThemes
|
||||
@@ -30,9 +34,6 @@ export
|
||||
with,
|
||||
twinx,
|
||||
|
||||
@userplot,
|
||||
@shorthands,
|
||||
|
||||
pie,
|
||||
pie!,
|
||||
plot3d,
|
||||
@@ -51,6 +52,8 @@ export
|
||||
yflip!,
|
||||
xaxis!,
|
||||
yaxis!,
|
||||
xgrid!,
|
||||
ygrid!,
|
||||
|
||||
xlims,
|
||||
ylims,
|
||||
@@ -107,22 +110,43 @@ export
|
||||
# ---------------------------------------------------------
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
import Measures
|
||||
module PlotMeasures
|
||||
import Measures
|
||||
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
|
||||
const BBox = Measures.Absolute2DBox
|
||||
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
|
||||
|
||||
# allow pixels and percentages
|
||||
const px = AbsoluteLength(0.254)
|
||||
const pct = Length{:pct, Float64}(1.0)
|
||||
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h
|
||||
end
|
||||
|
||||
using .PlotMeasures
|
||||
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
|
||||
# ---------------------------------------------------------
|
||||
|
||||
include("types.jl")
|
||||
@@ -138,25 +162,14 @@ 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
|
||||
@@ -184,33 +197,65 @@ end
|
||||
@shorthands quiver
|
||||
@shorthands curves
|
||||
|
||||
"Plot a pie diagram"
|
||||
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
|
||||
"Plot with seriestype :path3d"
|
||||
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
|
||||
|
||||
"Add title to an existing plot"
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
|
||||
"Add xlabel to an existing plot"
|
||||
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
|
||||
|
||||
"Add ylabel to an existing plot"
|
||||
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
|
||||
|
||||
"Set xlims for an existing plot"
|
||||
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
|
||||
|
||||
"Set ylims for an existing plot"
|
||||
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
|
||||
|
||||
"Set zlims for an existing plot"
|
||||
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
|
||||
|
||||
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
|
||||
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
|
||||
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
|
||||
|
||||
|
||||
"Set xticks for an existing plot"
|
||||
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
|
||||
|
||||
"Set yticks for an existing plot"
|
||||
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
|
||||
|
||||
xticks!{T<:Real,S<:AbstractString}(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
|
||||
yticks!{T<:Real,S<:AbstractString}(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
|
||||
|
||||
"Add annotations to an existing plot"
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
|
||||
|
||||
"Flip the current plots' x axis"
|
||||
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
|
||||
|
||||
"Flip the current plots' y axis"
|
||||
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
|
||||
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
|
||||
|
||||
let PlotOrSubplot = Union{Plot, Subplot}
|
||||
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
@@ -228,6 +273,8 @@ let PlotOrSubplot = Union{Plot, Subplot}
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
|
||||
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
|
||||
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
|
||||
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
|
||||
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
|
||||
@@ -241,10 +288,8 @@ end
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
function __init__()
|
||||
setup_ijulia()
|
||||
setup_atom()
|
||||
|
||||
# for compatibility with Requires.jl:
|
||||
@init begin
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
default(k, v)
|
||||
|
||||
+7
-2
@@ -1,4 +1,4 @@
|
||||
|
||||
"Represents an animation object"
|
||||
immutable Animation
|
||||
dir::String
|
||||
frames::Vector{String}
|
||||
@@ -9,6 +9,11 @@ function Animation()
|
||||
Animation(tmpdir, String[])
|
||||
end
|
||||
|
||||
"""
|
||||
frame(animation[, plot])
|
||||
|
||||
Add a plot (the current plot if not specified) to an existing animation
|
||||
"""
|
||||
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
@@ -81,7 +86,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString;
|
||||
catch err
|
||||
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
|
||||
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
|
||||
You may also need to install the imagemagick c++ library through your operating system.
|
||||
You may also need to install the imagemagick c++ library through your operating system.
|
||||
Will try ffmpeg, but it's lower quality...)""")
|
||||
|
||||
# low quality
|
||||
|
||||
+9
-5
@@ -21,7 +21,7 @@ const _arg_desc = KW(
|
||||
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
|
||||
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
|
||||
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto. For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
|
||||
:smooth => "Bool. Add a regression line?",
|
||||
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
|
||||
:x => "Various. Input data. First Dimension",
|
||||
@@ -40,7 +40,7 @@ const _arg_desc = KW(
|
||||
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
|
||||
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
|
||||
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
|
||||
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a PDF with integral of 1) and :density (only normalize in respect to bin sizes).",
|
||||
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
|
||||
:weights => "AbstractVector. Used in histogram types for weighted counts.",
|
||||
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
|
||||
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
|
||||
@@ -76,7 +76,6 @@ const _arg_desc = KW(
|
||||
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
|
||||
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
|
||||
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
|
||||
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
|
||||
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
|
||||
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
|
||||
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
|
||||
@@ -84,7 +83,6 @@ const _arg_desc = KW(
|
||||
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
|
||||
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
|
||||
:legendfont => "Font. Font of legend items.",
|
||||
:grid => "Bool. Show the grid lines?",
|
||||
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
|
||||
:projection => "Symbol or String. '3d' or 'polar'",
|
||||
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
|
||||
@@ -95,6 +93,7 @@ const _arg_desc = KW(
|
||||
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
|
||||
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
|
||||
:colorbar_title => "String. Title of colorbar.",
|
||||
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
|
||||
|
||||
# axis args
|
||||
:guide => "String. Axis guide (label).",
|
||||
@@ -111,5 +110,10 @@ const _arg_desc = KW(
|
||||
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
|
||||
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
|
||||
:mirror => "Bool. Switch the side of the tick labels (right or top).",
|
||||
|
||||
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
|
||||
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
|
||||
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
|
||||
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
|
||||
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
|
||||
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`"
|
||||
)
|
||||
|
||||
+134
-17
@@ -80,9 +80,13 @@ const _typeAliases = Dict{Symbol,Symbol}(
|
||||
|
||||
add_non_underscore_aliases!(_typeAliases)
|
||||
|
||||
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins)
|
||||
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
|
||||
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
|
||||
const _histogram_like = [:histogram, :barhist, :barbins]
|
||||
const _line_like = [:line, :path, :steppre, :steppost]
|
||||
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
|
||||
|
||||
like_histogram(seriestype::Symbol) = seriestype in _histogram_like
|
||||
like_line(seriestype::Symbol) = seriestype in _line_like
|
||||
like_surface(seriestype::Symbol) = seriestype in _surface_like
|
||||
|
||||
is3d(seriestype::Symbol) = seriestype in _3dTypes
|
||||
is3d(series::Series) = is3d(series.d)
|
||||
@@ -163,6 +167,34 @@ const _scaleAliases = Dict{Symbol,Symbol}(
|
||||
:log => :log10,
|
||||
)
|
||||
|
||||
const _allGridSyms = [:x, :y, :z,
|
||||
:xy, :xz, :yx, :yz, :zx, :zy,
|
||||
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
|
||||
:all, :both, :on,
|
||||
:none, :off,]
|
||||
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
|
||||
hasgrid(arg::Void, letter) = false
|
||||
hasgrid(arg::Bool, letter) = arg
|
||||
function hasgrid(arg::Symbol, letter)
|
||||
if arg in _allGridSyms
|
||||
arg in (:all, :both, :on) || contains(string(arg), string(letter))
|
||||
else
|
||||
warn("Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead.")
|
||||
true
|
||||
end
|
||||
end
|
||||
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
|
||||
|
||||
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
|
||||
const _framestyleAliases = Dict{Symbol, Symbol}(
|
||||
:frame => :box,
|
||||
:border => :box,
|
||||
:on => :box,
|
||||
:transparent => :semi,
|
||||
:semitransparent => :semi,
|
||||
)
|
||||
|
||||
const _bar_width = 0.8
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
const _series_defaults = KW(
|
||||
@@ -172,7 +204,7 @@ const _series_defaults = KW(
|
||||
:seriestype => :path,
|
||||
:linestyle => :solid,
|
||||
:linewidth => :auto,
|
||||
:linecolor => :match,
|
||||
:linecolor => :auto,
|
||||
:linealpha => nothing,
|
||||
:fillrange => nothing, # ribbons, areas, etc
|
||||
:fillcolor => :match,
|
||||
@@ -214,6 +246,7 @@ const _series_defaults = KW(
|
||||
: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
|
||||
:stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride.
|
||||
)
|
||||
|
||||
|
||||
@@ -247,7 +280,6 @@ const _subplot_defaults = KW(
|
||||
:background_color_inside => :match, # background inside grid
|
||||
:foreground_color_subplot => :match, # default for other fg colors... match takes plot default
|
||||
:foreground_color_legend => :match, # foreground of legend
|
||||
:foreground_color_grid => :match, # grid color
|
||||
:foreground_color_title => :match, # title color
|
||||
:color_palette => :auto,
|
||||
:legend => :best,
|
||||
@@ -255,7 +287,6 @@ const _subplot_defaults = KW(
|
||||
:colorbar => :legend,
|
||||
:clims => :auto,
|
||||
:legendfont => font(8),
|
||||
:grid => true,
|
||||
:annotations => [], # annotation tuples... list of (x,y,annotation)
|
||||
:projection => :none, # can also be :polar or :3d
|
||||
:aspect_ratio => :none, # choose from :none or :equal
|
||||
@@ -266,6 +297,7 @@ const _subplot_defaults = KW(
|
||||
:bottom_margin => :match,
|
||||
:subplot_index => -1,
|
||||
:colorbar_title => "",
|
||||
:framestyle => :axes,
|
||||
)
|
||||
|
||||
const _axis_defaults = KW(
|
||||
@@ -285,6 +317,12 @@ const _axis_defaults = KW(
|
||||
:discrete_values => [],
|
||||
:formatter => :auto,
|
||||
:mirror => false,
|
||||
:grid => true,
|
||||
:foreground_color_grid => :match, # grid color
|
||||
:gridalpha => 0.1,
|
||||
:gridstyle => :solid,
|
||||
:gridlinewidth => 0.5,
|
||||
:tick_direction => :in,
|
||||
)
|
||||
|
||||
const _suppress_warnings = Set{Symbol}([
|
||||
@@ -336,6 +374,12 @@ const _all_defaults = KW[
|
||||
_axis_defaults_byletter
|
||||
]
|
||||
|
||||
# to be able to reset font sizes to initial values
|
||||
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefont].pointsize,
|
||||
:legendfont => _subplot_defaults[:legendfont].pointsize,
|
||||
:tickfont => _axis_defaults[:tickfont].pointsize,
|
||||
:guidefont => _axis_defaults[:guidefont].pointsize)
|
||||
|
||||
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
|
||||
|
||||
RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
|
||||
@@ -396,7 +440,7 @@ add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_co
|
||||
add_aliases(:foreground_color_axis, :fg_axis, :fgaxis, :fgcolor_axis, :fg_color_axis, :foreground_axis,
|
||||
:foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor)
|
||||
add_aliases(:foreground_color_border, :fg_border, :fgborder, :fgcolor_border, :fg_color_border, :foreground_border,
|
||||
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor, :border)
|
||||
:foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor)
|
||||
add_aliases(:foreground_color_text, :fg_text, :fgtext, :fgcolor_text, :fg_color_text, :foreground_text,
|
||||
:foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor)
|
||||
add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_color_guide, :foreground_guide,
|
||||
@@ -408,6 +452,7 @@ add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
|
||||
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
|
||||
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
|
||||
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
|
||||
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
|
||||
|
||||
# series attributes
|
||||
add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt)
|
||||
@@ -463,7 +508,11 @@ add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesa
|
||||
add_aliases(:html_output_format, :format, :fmt, :html_format)
|
||||
add_aliases(:orientation, :direction, :dir)
|
||||
add_aliases(:inset_subplots, :inset, :floating)
|
||||
|
||||
add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str)
|
||||
add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw)
|
||||
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
|
||||
add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border)
|
||||
add_aliases(:tick_direction, :tickdirection, :tick_dir, :tickdir, :tick_orientation, :tickorientation, :tick_or, :tickor)
|
||||
|
||||
# add all pluralized forms to the _keyAliases dict
|
||||
for arg in keys(_series_defaults)
|
||||
@@ -482,7 +531,6 @@ end
|
||||
`default(; kw...)` will set the current default value for each key/value pair
|
||||
`default(d, key)` returns the key from d if it exists, otherwise `default(key)`
|
||||
"""
|
||||
|
||||
function default(k::Symbol)
|
||||
k = get(_keyAliases, k, k)
|
||||
for defaults in _all_defaults
|
||||
@@ -522,7 +570,6 @@ function default(d::KW, k::Symbol)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# if arg is a valid color value, then set d[csym] and return true
|
||||
@@ -640,6 +687,36 @@ function processFillArg(d::KW, arg)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
function processGridArg!(d::KW, arg, letter)
|
||||
if arg in _allGridArgs || isa(arg, Bool)
|
||||
d[Symbol(letter, :grid)] = hasgrid(arg, letter)
|
||||
|
||||
elseif allStyles(arg)
|
||||
d[Symbol(letter, :gridstyle)] = arg
|
||||
|
||||
elseif typeof(arg) <: Stroke
|
||||
arg.width == nothing || (d[Symbol(letter, :gridlinewidth)] = arg.width)
|
||||
arg.color == nothing || (d[Symbol(letter, :foreground_color_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color))
|
||||
arg.alpha == nothing || (d[Symbol(letter, :gridalpha)] = arg.alpha)
|
||||
arg.style == nothing || (d[Symbol(letter, :gridstyle)] = arg.style)
|
||||
|
||||
# linealpha
|
||||
elseif allAlphas(arg)
|
||||
d[Symbol(letter, :gridalpha)] = arg
|
||||
|
||||
# linewidth
|
||||
elseif allReals(arg)
|
||||
d[Symbol(letter, :gridlinewidth)] = arg
|
||||
|
||||
# color
|
||||
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
|
||||
warn("Skipped grid arg $arg.")
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
|
||||
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
|
||||
_replace_markershape(shape) = shape
|
||||
@@ -661,6 +738,7 @@ function preprocessArgs!(d::KW)
|
||||
if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
|
||||
d[:ticks] = nothing
|
||||
d[:foreground_color_border] = RGBA(0,0,0,0)
|
||||
d[:foreground_color_axis] = RGBA(0,0,0,0)
|
||||
d[:grid] = false
|
||||
delete!(d, :axis)
|
||||
end
|
||||
@@ -683,6 +761,22 @@ function preprocessArgs!(d::KW)
|
||||
end
|
||||
end
|
||||
|
||||
# handle grid args common to all axes
|
||||
args = pop!(d, :grid, ())
|
||||
for arg in wraptuple(args)
|
||||
for letter in (:x, :y, :z)
|
||||
processGridArg!(d, arg, letter)
|
||||
end
|
||||
end
|
||||
# handle individual axes grid args
|
||||
for letter in (:x, :y, :z)
|
||||
gridsym = Symbol(letter, :grid)
|
||||
args = pop!(d, gridsym, ())
|
||||
for arg in wraptuple(args)
|
||||
processGridArg!(d, arg, letter)
|
||||
end
|
||||
end
|
||||
|
||||
# handle line args
|
||||
for arg in wraptuple(pop!(d, :line, ()))
|
||||
processLineArg(d, arg)
|
||||
@@ -701,6 +795,9 @@ function preprocessArgs!(d::KW)
|
||||
delete!(d, :marker)
|
||||
if haskey(d, :markershape)
|
||||
d[:markershape] = _replace_markershape(d[:markershape])
|
||||
if d[:markershape] == :none && d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
elseif anymarker
|
||||
d[:markershape_to_add] = :circle # add it after _apply_recipe
|
||||
end
|
||||
@@ -744,6 +841,11 @@ function preprocessArgs!(d::KW)
|
||||
d[:colorbar] = convertLegendValue(d[:colorbar])
|
||||
end
|
||||
|
||||
# framestyle
|
||||
if haskey(d, :framestyle) && haskey(_framestyleAliases, d[:framestyle])
|
||||
d[:framestyle] = _framestyleAliases[d[:framestyle]]
|
||||
end
|
||||
|
||||
# warnings for moved recipes
|
||||
st = get(d, :seriestype, :path)
|
||||
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
|
||||
@@ -763,21 +865,29 @@ end
|
||||
|
||||
|
||||
# this is when given a vector-type of values to group by
|
||||
function extractGroupArgs(v::AVec, args...)
|
||||
function extractGroupArgs(v::AVec, args...; legendEntry = string)
|
||||
groupLabels = sort(collect(unique(v)))
|
||||
n = length(groupLabels)
|
||||
if n > 100
|
||||
warn("You created n=$n groups... Is that intended?")
|
||||
end
|
||||
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
|
||||
GroupBy(map(string, groupLabels), groupIds)
|
||||
GroupBy(map(legendEntry, groupLabels), groupIds)
|
||||
end
|
||||
|
||||
legendEntryFromTuple(ns::Tuple) = string(("$n " for n in ns)...)
|
||||
|
||||
# this is when given a tuple of vectors of values to group by
|
||||
function extractGroupArgs(vs::Tuple, args...)
|
||||
(vs == ()) && return GroupBy([""], [1:size(args[1],1)])
|
||||
v = collect(zip(vs...))
|
||||
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
|
||||
end
|
||||
|
||||
# expecting a mapping of "group label" to "group indices"
|
||||
function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...)
|
||||
groupLabels = sortedkeys(idxmap)
|
||||
groupIds = VecI[collect(idxmap[k]) for k in groupLabels]
|
||||
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
|
||||
GroupBy(groupLabels, groupIds)
|
||||
end
|
||||
|
||||
@@ -935,7 +1045,6 @@ const _match_map = KW(
|
||||
:background_color_legend => :background_color_subplot,
|
||||
:background_color_inside => :background_color_subplot,
|
||||
:foreground_color_legend => :foreground_color_subplot,
|
||||
:foreground_color_grid => :foreground_color_subplot,
|
||||
:foreground_color_title => :foreground_color_subplot,
|
||||
:left_margin => :margin,
|
||||
:top_margin => :margin,
|
||||
@@ -949,6 +1058,7 @@ const _match_map2 = KW(
|
||||
:foreground_color_subplot => :foreground_color,
|
||||
:foreground_color_axis => :foreground_color_subplot,
|
||||
:foreground_color_border => :foreground_color_subplot,
|
||||
:foreground_color_grid => :foreground_color_subplot,
|
||||
:foreground_color_guide => :foreground_color_subplot,
|
||||
:foreground_color_text => :foreground_color_subplot,
|
||||
)
|
||||
@@ -1083,7 +1193,6 @@ function _update_subplot_colors(sp::Subplot)
|
||||
# foreground colors
|
||||
color_or_nothing!(sp.attr, :foreground_color_subplot)
|
||||
color_or_nothing!(sp.attr, :foreground_color_legend)
|
||||
color_or_nothing!(sp.attr, :foreground_color_grid)
|
||||
color_or_nothing!(sp.attr, :foreground_color_title)
|
||||
return
|
||||
end
|
||||
@@ -1135,6 +1244,7 @@ function _update_axis_colors(axis::Axis)
|
||||
color_or_nothing!(axis.d, :foreground_color_border)
|
||||
color_or_nothing!(axis.d, :foreground_color_guide)
|
||||
color_or_nothing!(axis.d, :foreground_color_text)
|
||||
color_or_nothing!(axis.d, :foreground_color_grid)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1171,6 +1281,8 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
has_black_border_for_default(st) = error("The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.")
|
||||
has_black_border_for_default(st::Function) = error("The seriestype attribute only accepts Symbols, you passed the function $st.")
|
||||
function has_black_border_for_default(st::Symbol)
|
||||
like_histogram(st) || st in (:hexbin, :bar, :shape)
|
||||
end
|
||||
@@ -1240,12 +1352,14 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
# update other colors
|
||||
for s in (:line, :marker, :fill)
|
||||
csym, asym = Symbol(s,:color), Symbol(s,:alpha)
|
||||
d[csym] = if d[csym] == :match
|
||||
d[csym] = if d[csym] == :auto
|
||||
plot_color(if has_black_border_for_default(d[:seriestype]) && s == :line
|
||||
sp[:foreground_color_subplot]
|
||||
else
|
||||
d[:seriescolor]
|
||||
end, d[asym])
|
||||
elseif d[csym] == :match
|
||||
plot_color(d[:seriescolor], d[asym])
|
||||
else
|
||||
getSeriesRGBColor(d[csym], d[asym], sp, plotIndex)
|
||||
end
|
||||
@@ -1258,13 +1372,16 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
getSeriesRGBColor(d[:markerstrokecolor], d[:markerstrokealpha], sp, plotIndex)
|
||||
end
|
||||
|
||||
# if marker_z or line_z are set, ensure we have a gradient
|
||||
# if marker_z, fill_z or line_z are set, ensure we have a gradient
|
||||
if d[:marker_z] != nothing
|
||||
ensure_gradient!(d, :markercolor, :markeralpha)
|
||||
end
|
||||
if d[:line_z] != nothing
|
||||
ensure_gradient!(d, :linecolor, :linealpha)
|
||||
end
|
||||
if d[:fill_z] != nothing
|
||||
ensure_gradient!(d, :fillcolor, :fillalpha)
|
||||
end
|
||||
|
||||
# scatter plots don't have a line, but must have a shape
|
||||
if d[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d)
|
||||
|
||||
+95
-39
@@ -118,7 +118,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))
|
||||
ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
|
||||
|
||||
|
||||
const _scale_funcs = Dict{Symbol,Function}(
|
||||
@@ -181,15 +181,27 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
|
||||
end
|
||||
|
||||
# get a list of well-laid-out ticks
|
||||
scaled_ticks = if ticks == nothing
|
||||
optimize_ticks(
|
||||
if ticks == nothing
|
||||
scaled_ticks = optimize_ticks(
|
||||
sf(amin),
|
||||
sf(amax);
|
||||
k_min = 5, # minimum number of ticks
|
||||
k_min = 4, # minimum number of ticks
|
||||
k_max = 8, # maximum number of ticks
|
||||
)[1]
|
||||
elseif typeof(ticks) <: Int
|
||||
scaled_ticks, viewmin, viewmax = optimize_ticks(
|
||||
sf(amin),
|
||||
sf(amax);
|
||||
k_min = ticks, # minimum number of ticks
|
||||
k_max = ticks, # maximum number of ticks
|
||||
k_ideal = ticks,
|
||||
# `strict_span = false` rewards cases where the span of the
|
||||
# chosen ticks is not too much bigger than amin - amax:
|
||||
strict_span = false,
|
||||
)
|
||||
axis[:lims] = map(invscalefunc(scale), (viewmin, viewmax))
|
||||
else
|
||||
map(sf, filter(t -> amin <= t <= amax, ticks))
|
||||
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
|
||||
end
|
||||
unscaled_ticks = map(invscalefunc(scale), scaled_ticks)
|
||||
|
||||
@@ -216,7 +228,7 @@ end
|
||||
|
||||
# return (continuous_values, discrete_values) for the ticks on this axis
|
||||
function get_ticks(axis::Axis)
|
||||
ticks = axis[:ticks]
|
||||
ticks = _transform_ticks(axis[:ticks])
|
||||
ticks in (nothing, false) && return nothing
|
||||
|
||||
dvals = axis[:discrete_values]
|
||||
@@ -226,7 +238,7 @@ function get_ticks(axis::Axis)
|
||||
elseif ticks == :auto
|
||||
# compute optimal ticks and labels
|
||||
optimal_ticks_and_labels(axis)
|
||||
elseif typeof(ticks) <: AVec
|
||||
elseif typeof(ticks) <: Union{AVec, Int}
|
||||
# override ticks, but get the labels
|
||||
optimal_ticks_and_labels(axis, ticks)
|
||||
elseif typeof(ticks) <: NTuple{2, Any}
|
||||
@@ -246,6 +258,10 @@ function get_ticks(axis::Axis)
|
||||
end
|
||||
end
|
||||
|
||||
_transform_ticks(ticks) = ticks
|
||||
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
|
||||
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -349,11 +365,11 @@ 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] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
|
||||
end
|
||||
axis = sp.attr[Symbol(dsym, :axis)]
|
||||
expand_extrema!(axis, ignoreNaN_maximum(data) + 0.5maximum(bw))
|
||||
expand_extrema!(axis, ignoreNaN_minimum(data) - 0.5minimum(bw))
|
||||
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
|
||||
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
|
||||
end
|
||||
|
||||
end
|
||||
@@ -490,38 +506,78 @@ function axis_drawing_info(sp::Subplot)
|
||||
ymin, ymax = axis_limits(yaxis)
|
||||
xticks = get_ticks(xaxis)
|
||||
yticks = get_ticks(yaxis)
|
||||
spine_segs = Segments(2)
|
||||
grid_segs = Segments(2)
|
||||
xaxis_segs = Segments(2)
|
||||
yaxis_segs = Segments(2)
|
||||
xtick_segs = Segments(2)
|
||||
ytick_segs = Segments(2)
|
||||
xgrid_segs = Segments(2)
|
||||
ygrid_segs = Segments(2)
|
||||
xborder_segs = Segments(2)
|
||||
yborder_segs = Segments(2)
|
||||
|
||||
if !(xaxis[:ticks] in (nothing, false))
|
||||
f = scalefunc(yaxis[:scale])
|
||||
invf = invscalefunc(yaxis[:scale])
|
||||
t1 = invf(f(ymin) + 0.015*(f(ymax)-f(ymin)))
|
||||
t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin)))
|
||||
if !(sp[:framestyle] == :none)
|
||||
# xaxis
|
||||
sp[:framestyle] in (:grid, :origin, :zerolines) || push!(xaxis_segs, (xmin,ymin), (xmax,ymin)) # bottom spine / xaxis
|
||||
if sp[:framestyle] in (:origin, :zerolines)
|
||||
push!(xaxis_segs, (xmin, 0.0), (xmax, 0.0))
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && length(xticks) > 1
|
||||
showticks = xticks[1] .!= 0
|
||||
xticks = (xticks[1][showticks], xticks[2][showticks])
|
||||
end
|
||||
end
|
||||
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin,ymax), (xmax,ymax)) # top spine
|
||||
if !(xaxis[:ticks] in (nothing, false))
|
||||
f = scalefunc(yaxis[:scale])
|
||||
invf = invscalefunc(yaxis[:scale])
|
||||
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
|
||||
t1 = invf(f(ymin) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
|
||||
t2 = invf(f(ymax) - 0.015 * (f(ymax) - f(ymin)) * ticks_in)
|
||||
t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
|
||||
|
||||
push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine
|
||||
# push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine
|
||||
for xtick in xticks[1]
|
||||
push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick
|
||||
push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid
|
||||
# push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick
|
||||
for xtick in xticks[1]
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
(0, t3)
|
||||
else
|
||||
xaxis[:mirror] ? (ymax, t2) : (ymin, t1)
|
||||
end
|
||||
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
|
||||
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
|
||||
xaxis[:grid] && push!(xgrid_segs, (xtick, t1), (xtick, t2)) # vertical grid
|
||||
end
|
||||
end
|
||||
|
||||
# yaxis
|
||||
sp[:framestyle] in (:grid, :origin, :zerolines) || push!(yaxis_segs, (xmin,ymin), (xmin,ymax)) # left spine / yaxis
|
||||
if sp[:framestyle] in (:origin, :zerolines)
|
||||
push!(yaxis_segs, (0.0, ymin), (0.0, ymax))
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && length(yticks) > 1
|
||||
showticks = yticks[1] .!= 0
|
||||
yticks = (yticks[1][showticks], yticks[2][showticks])
|
||||
end
|
||||
end
|
||||
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (xmax,ymin), (xmax,ymax)) # right spine
|
||||
if !(yaxis[:ticks] in (nothing, false))
|
||||
f = scalefunc(xaxis[:scale])
|
||||
invf = invscalefunc(xaxis[:scale])
|
||||
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
|
||||
t1 = invf(f(xmin) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
|
||||
t2 = invf(f(xmax) - 0.015 * (f(xmax) - f(xmin)) * ticks_in)
|
||||
t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
|
||||
|
||||
for ytick in yticks[1]
|
||||
tick_start, tick_stop = if sp[:framestyle] == :origin
|
||||
(0, t3)
|
||||
else
|
||||
yaxis[:mirror] ? (xmax, t2) : (xmin, t1)
|
||||
end
|
||||
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
|
||||
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
|
||||
yaxis[:grid] && push!(ygrid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if !(yaxis[:ticks] in (nothing, false))
|
||||
f = scalefunc(xaxis[:scale])
|
||||
invf = invscalefunc(xaxis[:scale])
|
||||
t1 = invf(f(xmin) + 0.015*(f(xmax)-f(xmin)))
|
||||
t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin)))
|
||||
|
||||
push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine
|
||||
# push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine
|
||||
for ytick in yticks[1]
|
||||
push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick
|
||||
push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid
|
||||
# push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick
|
||||
end
|
||||
end
|
||||
|
||||
xticks, yticks, spine_segs, grid_segs
|
||||
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs
|
||||
end
|
||||
|
||||
@@ -6,7 +6,10 @@ const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
|
||||
const _backends = Symbol[]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
|
||||
"Returns a list of supported backends"
|
||||
backends() = _backends
|
||||
|
||||
"Returns the name of the current backend"
|
||||
backend_name() = CURRENT_BACKEND.sym
|
||||
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
|
||||
|
||||
|
||||
+98
-58
@@ -24,7 +24,8 @@ const _glvisualize_attr = merge_with_base_supported([
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :colorbar,
|
||||
:marker_z,
|
||||
:line_z,
|
||||
:levels,
|
||||
@@ -38,7 +39,9 @@ const _glvisualize_attr = merge_with_base_supported([
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:hover
|
||||
:hover,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
])
|
||||
const _glvisualize_seriestype = [
|
||||
:path, :shape,
|
||||
@@ -58,7 +61,7 @@ const _glvisualize_scale = [:identity, :ln, :log2, :log10]
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval begin
|
||||
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
|
||||
import FileIO, Images
|
||||
export GLVisualize
|
||||
import Reactive: Signal
|
||||
@@ -66,9 +69,8 @@ function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
import GLVisualize: visualize
|
||||
import Plots.GL
|
||||
import UnicodeFun
|
||||
Plots.slice_arg(img::Images.AbstractImage, idx::Int) = img
|
||||
Plots.slice_arg{C<:Colorant}(img::Matrix{C}, idx::Int) = img
|
||||
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
|
||||
is_marker_supported{Img<:Images.AbstractImage}(::GLVisualizeBackend, shape::Union{Vector{Img}, Img}) = true
|
||||
is_marker_supported{C<:Colorant}(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) = true
|
||||
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
|
||||
const GL = Plots
|
||||
@@ -173,12 +175,12 @@ function gl_marker(shape)
|
||||
shape
|
||||
end
|
||||
function gl_marker(shape::Shape)
|
||||
points = Point2f0[Vec{2,Float32}(p) for p in zip(shape.x, shape.y)]
|
||||
points = Point2f0[GeometryTypes.Vec{2, Float32}(p) for p in zip(shape.x, shape.y)]
|
||||
bb = GeometryTypes.AABB(points)
|
||||
mini, maxi = minimum(bb), maximum(bb)
|
||||
w3 = maxi-mini
|
||||
origin, width = Point2f0(mini[1], mini[2]), Point2f0(w3[1], w3[2])
|
||||
map!(p -> ((p - origin) ./ width) - 0.5f0, points) # normalize and center
|
||||
map!(p -> ((p - origin) ./ width) - 0.5f0, points, points) # normalize and center
|
||||
GeometryTypes.GLNormalMesh(points)
|
||||
end
|
||||
# create a marker/shape type
|
||||
@@ -212,13 +214,13 @@ function extract_limits(sp, d, kw_args)
|
||||
nothing
|
||||
end
|
||||
|
||||
to_vec{T <: FixedVector}(::Type{T}, vec::T) = vec
|
||||
to_vec{T <: FixedVector}(::Type{T}, s::Number) = T(s)
|
||||
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vec::T) = vec
|
||||
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, s::Number) = T(s)
|
||||
|
||||
to_vec{T <: FixedVector{2}}(::Type{T}, vec::FixedVector{3}) = T(vec[1], vec[2])
|
||||
to_vec{T <: FixedVector{3}}(::Type{T}, vec::FixedVector{2}) = T(vec[1], vec[2], 0)
|
||||
to_vec{T <: StaticArrays.StaticVector{2}}(::Type{T}, vec::StaticArrays.StaticVector{3}) = T(vec[1], vec[2])
|
||||
to_vec{T <: StaticArrays.StaticVector{3}}(::Type{T}, vec::StaticArrays.StaticVector{2}) = T(vec[1], vec[2], 0)
|
||||
|
||||
to_vec{T <: FixedVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
|
||||
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
|
||||
|
||||
function extract_marker(d, kw_args)
|
||||
dim = Plots.is3d(d) ? 3 : 2
|
||||
@@ -274,7 +276,7 @@ function extract_surface(d)
|
||||
map(_extract_surface, (d[:x], d[:y], d[:z]))
|
||||
end
|
||||
function topoints{P}(::Type{P}, array)
|
||||
P[x for x in zip(array...)]
|
||||
[P(x) for x in zip(array...)]
|
||||
end
|
||||
function extract_points(d)
|
||||
dim = is3d(d) ? 3 : 2
|
||||
@@ -304,7 +306,7 @@ function extract_any_color(d, kw_args)
|
||||
kw_args[:color_norm] = Vec2f0(clims)
|
||||
end
|
||||
elseif clims == :auto
|
||||
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(d[:y]))
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(d[:y]))
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -315,7 +317,7 @@ function extract_any_color(d, kw_args)
|
||||
kw_args[:color_norm] = Vec2f0(clims)
|
||||
end
|
||||
elseif clims == :auto
|
||||
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(d[:y]))
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(d[:y]))
|
||||
else
|
||||
error("Unsupported limits: $clims")
|
||||
end
|
||||
@@ -482,7 +484,7 @@ function hover(to_hover, to_display, window)
|
||||
end
|
||||
|
||||
function extract_extrema(d, kw_args)
|
||||
xmin, xmax = ignoreNaN_extrema(d[:x]); ymin, ymax = ignoreNaN_extrema(d[:y])
|
||||
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
|
||||
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
|
||||
nothing
|
||||
end
|
||||
@@ -509,7 +511,7 @@ function extract_colornorm(d, kw_args)
|
||||
else
|
||||
d[:y]
|
||||
end
|
||||
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(z))
|
||||
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(z))
|
||||
kw_args[:intensity] = map(Float32, collect(z))
|
||||
end
|
||||
end
|
||||
@@ -576,8 +578,10 @@ end
|
||||
|
||||
function align_offset(startpos, lastpos, atlas, rscale, font, align)
|
||||
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
|
||||
xmove = (lastpos-startpos)[1]+xscale
|
||||
if align == :top
|
||||
xmove = (lastpos-startpos)[1] + xscale
|
||||
if isa(align, GeometryTypes.Vec)
|
||||
return -Vec2f0(xmove, yscale) .* align
|
||||
elseif align == :top
|
||||
return -Vec2f0(xmove/2f0, yscale)
|
||||
elseif align == :right
|
||||
return -Vec2f0(xmove, yscale/2f0)
|
||||
@@ -586,11 +590,6 @@ function align_offset(startpos, lastpos, atlas, rscale, font, align)
|
||||
end
|
||||
end
|
||||
|
||||
function align_offset(startpos, lastpos, atlas, rscale, font, align::Vec)
|
||||
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
|
||||
xmove = (lastpos-startpos)[1] + xscale
|
||||
return -Vec2f0(xmove, yscale) .* align
|
||||
end
|
||||
|
||||
function alignment2num(x::Symbol)
|
||||
(x in (:hcenter, :vcenter)) && return 0.5
|
||||
@@ -606,7 +605,7 @@ end
|
||||
pointsize(font) = font.pointsize * 2
|
||||
|
||||
function draw_ticks(
|
||||
axis, ticks, isx, lims, m, text = "",
|
||||
axis, ticks, isx, isorigin, lims, m, text = "",
|
||||
positions = Point2f0[], offsets=Vec2f0[]
|
||||
)
|
||||
sz = pointsize(axis[:tickfont])
|
||||
@@ -624,7 +623,11 @@ function draw_ticks(
|
||||
for (cv, dv) in zip(ticks...)
|
||||
|
||||
x, y = cv, lims[1]
|
||||
xy = isx ? (x, y) : (y, x)
|
||||
xy = if isorigin
|
||||
isx ? (x, 0) : (0, x)
|
||||
else
|
||||
isx ? (x, y) : (y, x)
|
||||
end
|
||||
_pos = m * GeometryTypes.Vec4f0(xy[1], xy[2], 0, 1)
|
||||
startpos = Point2f0(_pos[1], _pos[2]) - axis_gap
|
||||
str = string(dv)
|
||||
@@ -638,7 +641,7 @@ function draw_ticks(
|
||||
position = GLVisualize.calc_position(str, startpos, sz, font, atlas)
|
||||
offset = GLVisualize.calc_offset(str, sz, font, atlas)
|
||||
alignoff = align_offset(startpos, last(position), atlas, sz, font, align)
|
||||
map!(position) do pos
|
||||
map!(position, position) do pos
|
||||
pos .+ alignoff
|
||||
end
|
||||
append!(positions, position)
|
||||
@@ -660,7 +663,7 @@ function glvisualize_text(position, text, kw_args)
|
||||
offset = GLVisualize.calc_offset(text.str, rscale, font, atlas)
|
||||
alignoff = align_offset(startpos, last(position), atlas, rscale, font, text_align)
|
||||
|
||||
map!(position) do pos
|
||||
map!(position, position) do pos
|
||||
pos .+ alignoff
|
||||
end
|
||||
kw_args[:position] = position
|
||||
@@ -680,31 +683,62 @@ function text_model(font, pivot)
|
||||
end
|
||||
end
|
||||
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
|
||||
xticks, yticks, spine_segs, grid_segs = Plots.axis_drawing_info(sp)
|
||||
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
|
||||
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
|
||||
|
||||
c = Colors.color(Plots.gl_color(sp[:foreground_color_grid]))
|
||||
xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
|
||||
ygc = Colors.color(Plots.gl_color(yaxis[:foreground_color_grid]))
|
||||
axis_vis = []
|
||||
if sp[:grid]
|
||||
grid = draw_grid_lines(sp, grid_segs, 1f0, :dot, model, RGBA(c, 0.3f0))
|
||||
if xaxis[:grid]
|
||||
grid = draw_grid_lines(sp, xgrid_segs, xaxis[:gridlinewidth], xaxis[:gridstyle], model, RGBA(xgc, xaxis[:gridalpha]))
|
||||
push!(axis_vis, grid)
|
||||
end
|
||||
if alpha(xaxis[:foreground_color_border]) > 0
|
||||
spine = draw_grid_lines(sp, spine_segs, 1f0, :solid, model, RGBA(c, 1.0f0))
|
||||
if yaxis[:grid]
|
||||
grid = draw_grid_lines(sp, ygrid_segs, yaxis[:gridlinewidth], yaxis[:gridstyle], model, RGBA(ygc, yaxis[:gridalpha]))
|
||||
push!(axis_vis, grid)
|
||||
end
|
||||
|
||||
xac = Colors.color(Plots.gl_color(xaxis[:foreground_color_axis]))
|
||||
yac = Colors.color(Plots.gl_color(yaxis[:foreground_color_axis]))
|
||||
if alpha(xaxis[:foreground_color_axis]) > 0
|
||||
spine = draw_grid_lines(sp, xspine_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
|
||||
push!(axis_vis, spine)
|
||||
end
|
||||
if alpha(yaxis[:foreground_color_axis]) > 0
|
||||
spine = draw_grid_lines(sp, yspine_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
|
||||
push!(axis_vis, spine)
|
||||
end
|
||||
if sp[:framestyle] in (:zerolines, :grid)
|
||||
if alpha(xaxis[:foreground_color_grid]) > 0
|
||||
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xgc, xaxis[:gridalpha]))
|
||||
push!(axis_vis, spine)
|
||||
end
|
||||
if alpha(yaxis[:foreground_color_grid]) > 0
|
||||
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(ygc, yaxis[:gridalpha]))
|
||||
push!(axis_vis, spine)
|
||||
end
|
||||
else
|
||||
if alpha(xaxis[:foreground_color_axis]) > 0
|
||||
spine = draw_grid_lines(sp, xtick_segs, 1f0, :solid, model, RGBA(xac, 1.0f0))
|
||||
push!(axis_vis, spine)
|
||||
end
|
||||
if alpha(yaxis[:foreground_color_axis]) > 0
|
||||
spine = draw_grid_lines(sp, ytick_segs, 1f0, :solid, model, RGBA(yac, 1.0f0))
|
||||
push!(axis_vis, spine)
|
||||
end
|
||||
end
|
||||
fcolor = Plots.gl_color(xaxis[:foreground_color_axis])
|
||||
|
||||
xlim = Plots.axis_limits(xaxis)
|
||||
ylim = Plots.axis_limits(yaxis)
|
||||
|
||||
if !(xaxis[:ticks] in (nothing, false, :none))
|
||||
if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none)
|
||||
ticklabels = map(model) do m
|
||||
mirror = xaxis[:mirror]
|
||||
t, positions, offsets = draw_ticks(xaxis, xticks, true, ylim, m)
|
||||
t, positions, offsets = draw_ticks(xaxis, xticks, true, sp[:framestyle] == :origin, ylim, m)
|
||||
mirror = xaxis[:mirror]
|
||||
t, positions, offsets = draw_ticks(
|
||||
yaxis, yticks, false, xlim, m,
|
||||
yaxis, yticks, false, sp[:framestyle] == :origin, xlim, m,
|
||||
t, positions, offsets
|
||||
)
|
||||
end
|
||||
@@ -718,6 +752,15 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
|
||||
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
|
||||
end
|
||||
|
||||
xbc = Colors.color(Plots.gl_color(xaxis[:foreground_color_border]))
|
||||
ybc = Colors.color(Plots.gl_color(yaxis[:foreground_color_border]))
|
||||
intensity = sp[:framestyle] == :semi ? 0.5f0 : 1.0f0
|
||||
if sp[:framestyle] in (:box, :semi)
|
||||
xborder = draw_grid_lines(sp, xborder_segs, intensity, :solid, model, RGBA(xbc, intensity))
|
||||
yborder = draw_grid_lines(sp, yborder_segs, intensity, :solid, model, RGBA(ybc, intensity))
|
||||
push!(axis_vis, xborder, yborder)
|
||||
end
|
||||
|
||||
area_w = GeometryTypes.widths(area)
|
||||
if sp[:title] != ""
|
||||
tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title])
|
||||
@@ -781,9 +824,9 @@ function gl_bar(d, kw_args)
|
||||
# compute half-width of bars
|
||||
bw = nothing
|
||||
hw = if bw == nothing
|
||||
ignoreNaN_mean(diff(x))
|
||||
ignorenan_mean(diff(x))
|
||||
else
|
||||
Float64[cycle(bw,i)*0.5 for i=1:length(x)]
|
||||
Float64[_cycle(bw,i)*0.5 for i=1:length(x)]
|
||||
end
|
||||
|
||||
# make fillto a vector... default fills to 0
|
||||
@@ -792,12 +835,12 @@ function gl_bar(d, kw_args)
|
||||
fillto = 0
|
||||
end
|
||||
# create the bar shapes by adding x/y segments
|
||||
positions, scales = Array(Point2f0, ny), Array(Vec2f0, ny)
|
||||
positions, scales = Array{Point2f0}(ny), Array{Vec2f0}(ny)
|
||||
m = Reactive.value(kw_args[:model])
|
||||
sx, sy = m[1,1], m[2,2]
|
||||
for i=1:ny
|
||||
center = x[i]
|
||||
hwi = abs(cycle(hw,i)); yi = y[i]; fi = cycle(fillto,i)
|
||||
hwi = abs(_cycle(hw,i)); yi = y[i]; fi = _cycle(fillto,i)
|
||||
if Plots.isvertical(d)
|
||||
sz = (hwi*sx, yi*sy)
|
||||
else
|
||||
@@ -833,7 +876,7 @@ function gl_boxplot(d, kw_args)
|
||||
sx, sy = m[1,1], m[2,2]
|
||||
for (i,glabel) in enumerate(glabels)
|
||||
# filter y
|
||||
values = y[filter(i -> cycle(x,i) == glabel, 1:length(y))]
|
||||
values = y[filter(i -> _cycle(x,i) == glabel, 1:length(y))]
|
||||
# compute quantiles
|
||||
q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5))
|
||||
# notch
|
||||
@@ -846,7 +889,7 @@ function gl_boxplot(d, kw_args)
|
||||
|
||||
# make the shape
|
||||
center = Plots.discrete_value!(d[:subplot][:xaxis], glabel)[1]
|
||||
hw = d[:bar_width] == nothing ? Plots._box_halfwidth*2 : cycle(d[:bar_width], i)
|
||||
hw = d[:bar_width] == nothing ? Plots._box_halfwidth*2 : _cycle(d[:bar_width], i)
|
||||
l, m, r = center - hw/2, center, center + hw/2
|
||||
|
||||
# internal nodes for notches
|
||||
@@ -864,7 +907,7 @@ function gl_boxplot(d, kw_args)
|
||||
end
|
||||
# change q1 and q5 to show outliers
|
||||
# using maximum and minimum values inside the limits
|
||||
q1, q5 = ignoreNaN_extrema(inside)
|
||||
q1, q5 = ignorenan_extrema(inside)
|
||||
end
|
||||
# Box
|
||||
if notch
|
||||
@@ -943,9 +986,9 @@ function scale_for_annotations!(series::Series, scaletype::Symbol = :pixels)
|
||||
# we use baseshape to overwrite the markershape attribute
|
||||
# with a list of custom shapes for each
|
||||
msw, msh = anns.scalefactor
|
||||
offsets = Array(Vec2f0, length(anns.strs))
|
||||
offsets = Array{Vec2f0}(length(anns.strs))
|
||||
series[:markersize] = map(1:length(anns.strs)) do i
|
||||
str = cycle(anns.strs, i)
|
||||
str = _cycle(anns.strs, i)
|
||||
# get the width and height of the string (in mm)
|
||||
sw, sh = text_size(str, anns.font.pointsize)
|
||||
|
||||
@@ -1058,7 +1101,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||
kw = copy(kw_args)
|
||||
fr = d[:fillrange]
|
||||
ps = if all(x-> x >= 0, diff(d[:x])) # if is monotonic
|
||||
vcat(points, Point2f0[(points[i][1], cycle(fr, i)) for i=length(points):-1:1])
|
||||
vcat(points, Point2f0[(points[i][1], _cycle(fr, i)) for i=length(points):-1:1])
|
||||
else
|
||||
points
|
||||
end
|
||||
@@ -1122,7 +1165,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||
anns = series[:series_annotations]
|
||||
for (x, y, str, font) in EachAnn(anns, d[:x], d[:y])
|
||||
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
|
||||
x, y = Reactive.value(model_m) * Vec{4, Float32}(x, y, 0, 1)
|
||||
x, y = Reactive.value(model_m) * GeometryTypes.Vec{4, Float32}(x, y, 0, 1)
|
||||
extract_font(font, txt_args)
|
||||
t = glvisualize_text(Point2f0(x, y), PlotText(str, font), txt_args)
|
||||
GLVisualize._view(t, sp_screen, camera = :perspective)
|
||||
@@ -1148,10 +1191,7 @@ function _show(io::IO, ::MIME"image/png", plt::Plot{GLVisualizeBackend})
|
||||
GLWindow.render_frame(GLWindow.rootscreen(plt.o))
|
||||
GLWindow.swapbuffers(plt.o)
|
||||
buff = GLWindow.screenbuffer(plt.o)
|
||||
png = Images.Image(map(RGB{U8}, buff),
|
||||
colorspace = "sRGB",
|
||||
spatialorder = ["y", "x"]
|
||||
)
|
||||
png = map(RGB{U8}, buff)
|
||||
FileIO.save(FileIO.Stream(FileIO.DataFormat{:PNG}, io), png)
|
||||
end
|
||||
|
||||
@@ -1231,7 +1271,7 @@ function gl_scatter(points, kw_args)
|
||||
if haskey(kw_args, :stroke_width)
|
||||
s = Reactive.value(kw_args[:scale])
|
||||
sw = kw_args[:stroke_width]
|
||||
if sw*5 > cycle(Reactive.value(s), 1)[1] # restrict marker stroke to 1/10th of scale (and handle arrays of scales)
|
||||
if sw*5 > _cycle(Reactive.value(s), 1)[1] # restrict marker stroke to 1/10th of scale (and handle arrays of scales)
|
||||
kw_args[:stroke_width] = s[1] / 5f0
|
||||
end
|
||||
end
|
||||
@@ -1309,8 +1349,8 @@ function gl_contour(x, y, z, kw_args)
|
||||
if kw_args[:fillrange] != nothing
|
||||
|
||||
delete!(kw_args, :intensity)
|
||||
I = GLVisualize.Intensity{1, Float32}
|
||||
main = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
|
||||
I = GLVisualize.Intensity{Float32}
|
||||
main = [I(z[j,i]) for i=1:size(z, 2), j=1:size(z, 1)]
|
||||
return visualize(main, Style(:default), kw_args)
|
||||
|
||||
else
|
||||
@@ -1318,7 +1358,7 @@ function gl_contour(x, y, z, kw_args)
|
||||
T = eltype(z)
|
||||
levels = Contour.contours(map(T, x), map(T, y), z, h)
|
||||
result = Point2f0[]
|
||||
zmin, zmax = get(kw_args, :limits, Vec2f0(ignoreNaN_extrema(z)))
|
||||
zmin, zmax = get(kw_args, :limits, Vec2f0(ignorenan_extrema(z)))
|
||||
cmap = get(kw_args, :color_map, get(kw_args, :color, RGBA{Float32}(0,0,0,1)))
|
||||
colors = RGBA{Float32}[]
|
||||
for c in levels.contours
|
||||
@@ -1339,10 +1379,10 @@ end
|
||||
|
||||
|
||||
function gl_heatmap(x,y,z, kw_args)
|
||||
get!(kw_args, :color_norm, Vec2f0(ignoreNaN_extrema(z)))
|
||||
get!(kw_args, :color_norm, Vec2f0(ignorenan_extrema(z)))
|
||||
get!(kw_args, :color_map, Plots.make_gradient(cgrad()))
|
||||
delete!(kw_args, :intensity)
|
||||
I = GLVisualize.Intensity{1, Float32}
|
||||
I = GLVisualize.Intensity{Float32}
|
||||
heatmap = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
|
||||
tex = GLAbstraction.Texture(heatmap, minfilter=:nearest)
|
||||
kw_args[:stroke_width] = 0f0
|
||||
|
||||
+270
-117
@@ -20,8 +20,9 @@ const _gr_attr = merge_with_base_supported([
|
||||
:title, :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :legendtitle, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
@@ -31,6 +32,8 @@ const _gr_attr = merge_with_base_supported([
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
])
|
||||
const _gr_seriestype = [
|
||||
:path, :scatter,
|
||||
@@ -124,10 +127,10 @@ 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)))
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -179,7 +182,7 @@ gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
|
||||
function gr_inqtext(x, y, s)
|
||||
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
|
||||
GR.inqtextext(x, y, s[2:end-1])
|
||||
elseif search(s, '\\') != 0 || search(s, '_') != 0 || search(s, '^') != 0
|
||||
elseif search(s, '\\') != 0
|
||||
GR.inqtextext(x, y, s)
|
||||
else
|
||||
GR.inqtext(x, y, s)
|
||||
@@ -191,7 +194,7 @@ gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
|
||||
function gr_text(x, y, s)
|
||||
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
|
||||
GR.mathtex(x, y, s[2:end-1])
|
||||
elseif search(s, '\\') != 0 || search(s, '_') != 0 || search(s, '^') != 0
|
||||
elseif search(s, '\\') != 0
|
||||
GR.textext(x, y, s)
|
||||
else
|
||||
GR.text(x, y, s)
|
||||
@@ -262,16 +265,21 @@ function gr_fill_viewport(vp::AVec{Float64}, c)
|
||||
end
|
||||
|
||||
|
||||
normalize_zvals(zv::Void) = zv
|
||||
function normalize_zvals(zv::AVec)
|
||||
vmin, vmax = ignoreNaN_extrema(zv)
|
||||
normalize_zvals(args...) = nothing
|
||||
function normalize_zvals(zv::AVec, clims::NTuple{2, <:Real})
|
||||
vmin, vmax = ignorenan_extrema(zv)
|
||||
isfinite(clims[1]) && (vmin = clims[1])
|
||||
isfinite(clims[2]) && (vmax = clims[2])
|
||||
if vmin == vmax
|
||||
zeros(length(zv))
|
||||
else
|
||||
(zv - vmin) ./ (vmax - vmin)
|
||||
clamp.((zv - vmin) ./ (vmax - vmin), 0, 1)
|
||||
end
|
||||
end
|
||||
|
||||
gr_alpha(α::Void) = 1
|
||||
gr_alpha(α::Real) = α
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# draw ONE Shape
|
||||
@@ -301,38 +309,42 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
|
||||
shapes = series[:markershape]
|
||||
if shapes != :none
|
||||
for i=1:length(x)
|
||||
msi = cycle(msize, i)
|
||||
shape = cycle(shapes, i)
|
||||
msi = _cycle(msize, i)
|
||||
shape = _cycle(shapes, 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
|
||||
gr_draw_marker(x[i], y[i], msi, shape)
|
||||
# don't draw filled area if marker shape is 1D
|
||||
if !(shape in (:hline, :vline, :+, :x))
|
||||
gr_draw_marker(x[i], y[i], msi, shape)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function gr_draw_markers(series::Series, x, y)
|
||||
function gr_draw_markers(series::Series, x, y, clims)
|
||||
isempty(x) && return
|
||||
mz = normalize_zvals(series[:marker_z])
|
||||
mz = normalize_zvals(series[:marker_z], clims)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
gr_draw_markers(series, x, y, series[:markersize], mz)
|
||||
if mz != nothing
|
||||
gr_colorbar(series[:subplot])
|
||||
if hascolorbar(series[:subplot])
|
||||
GR.setscale(0)
|
||||
gr_colorbar(series[:subplot], clims)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -353,7 +365,7 @@ function gr_set_fill(c) #, a)
|
||||
end
|
||||
|
||||
# this stores the conversion from a font pointsize to "percentage of window height" (which is what GR uses)
|
||||
const _gr_point_mult = zeros(1)
|
||||
const _gr_point_mult = 0.0018 * ones(1)
|
||||
|
||||
# set the font attributes... assumes _gr_point_mult has been populated already
|
||||
function gr_set_font(f::Font; halign = f.halign, valign = f.valign,
|
||||
@@ -384,7 +396,7 @@ end
|
||||
const viewport_plotarea = zeros(4)
|
||||
|
||||
# the size of the current plot in pixels
|
||||
const gr_plot_size = zeros(2)
|
||||
const gr_plot_size = [600.0, 400.0]
|
||||
|
||||
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
|
||||
viewport = zeros(4)
|
||||
@@ -436,11 +448,21 @@ end
|
||||
|
||||
# add the colorbar
|
||||
function gr_colorbar(sp::Subplot)
|
||||
if sp[:colorbar] != :none
|
||||
gr_set_viewport_cmap(sp)
|
||||
GR.colorbar()
|
||||
gr_set_viewport_plotarea()
|
||||
end
|
||||
gr_set_viewport_cmap(sp)
|
||||
GR.colorbar()
|
||||
gr_set_viewport_plotarea()
|
||||
end
|
||||
|
||||
function gr_colorbar(sp::Subplot, clims)
|
||||
xmin, xmax = gr_xy_axislims(sp)[1:2]
|
||||
gr_set_viewport_cmap(sp)
|
||||
l = zeros(Int32, 1, 256)
|
||||
l[1,:] = Int[round(Int, _i) for _i in linspace(1000, 1255, 256)]
|
||||
GR.setwindow(xmin, xmax, clims[1], clims[2])
|
||||
GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l)
|
||||
ztick = 0.5 * GR.tick(clims[1], clims[2])
|
||||
GR.axes(0, ztick, xmax, clims[1], 0, 1, 0.005)
|
||||
gr_set_viewport_plotarea()
|
||||
end
|
||||
|
||||
gr_view_xcenter() = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2])
|
||||
@@ -448,7 +470,6 @@ gr_view_ycenter() = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4])
|
||||
|
||||
function gr_legend_pos(s::Symbol,w,h)
|
||||
str = string(s)
|
||||
println(str)
|
||||
if str == "best"
|
||||
str = "topright"
|
||||
end
|
||||
@@ -534,17 +555,97 @@ function gr_display(plt::Plot)
|
||||
end
|
||||
|
||||
|
||||
function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
sp.minpad = (10mm,2mm,2mm,8mm)
|
||||
function gr_set_xticks_font(sp)
|
||||
flip = sp[:yaxis][:flip]
|
||||
mirror = sp[:xaxis][:mirror]
|
||||
gr_set_font(sp[:xaxis][:tickfont],
|
||||
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
|
||||
valign = (mirror ? :bottom : :top),
|
||||
color = sp[:xaxis][:foreground_color_axis],
|
||||
rotation = sp[:xaxis][:rotation])
|
||||
return flip, mirror
|
||||
end
|
||||
|
||||
|
||||
function gr_set_yticks_font(sp)
|
||||
flip = sp[:xaxis][:flip]
|
||||
mirror = sp[:yaxis][:mirror]
|
||||
gr_set_font(sp[:yaxis][:tickfont],
|
||||
halign = (mirror ? :left : :right),
|
||||
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
|
||||
color = sp[:yaxis][:foreground_color_axis],
|
||||
rotation = sp[:yaxis][:rotation])
|
||||
return flip, mirror
|
||||
end
|
||||
|
||||
function gr_get_ticks_size(ticks, i)
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
l = 0.0
|
||||
for (cv, dv) in zip(ticks...)
|
||||
tb = gr_inqtext(0, 0, string(dv))[i]
|
||||
tb_min, tb_max = extrema(tb)
|
||||
l = max(l, tb_max - tb_min)
|
||||
end
|
||||
GR.restorestate()
|
||||
return l
|
||||
end
|
||||
|
||||
function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
if !haskey(ENV, "GKSwstype")
|
||||
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
|
||||
ENV["GKSwstype"] = "svg"
|
||||
end
|
||||
end
|
||||
# Add margin given by the user
|
||||
leftpad = 2mm + sp[:left_margin]
|
||||
toppad = 2mm + sp[:top_margin]
|
||||
rightpad = 4mm + sp[:right_margin]
|
||||
bottompad = 2mm + sp[:bottom_margin]
|
||||
# Add margin for title
|
||||
if sp[:title] != ""
|
||||
toppad += 5mm
|
||||
end
|
||||
# Add margin for x and y ticks
|
||||
xticks, yticks = axis_drawing_info(sp)[1:2]
|
||||
if !(xticks in (nothing, false))
|
||||
flip, mirror = gr_set_xticks_font(sp)
|
||||
l = gr_get_ticks_size(xticks, 2)
|
||||
if mirror
|
||||
toppad += 1mm + gr_plot_size[2] * l * px
|
||||
else
|
||||
bottompad += 1mm + gr_plot_size[2] * l * px
|
||||
end
|
||||
end
|
||||
if !(yticks in (nothing, false))
|
||||
flip, mirror = gr_set_yticks_font(sp)
|
||||
l = gr_get_ticks_size(yticks, 1)
|
||||
if mirror
|
||||
rightpad += 1mm + gr_plot_size[1] * l * px
|
||||
else
|
||||
leftpad += 1mm + gr_plot_size[1] * l * px
|
||||
end
|
||||
end
|
||||
# Add margin for x label
|
||||
if sp[:xaxis][:guide] != ""
|
||||
bottompad += 4mm
|
||||
end
|
||||
# Add margin for y label
|
||||
if sp[:yaxis][:guide] != ""
|
||||
leftpad += 4mm
|
||||
end
|
||||
sp.minpad = (leftpad, toppad, rightpad, bottompad)
|
||||
end
|
||||
|
||||
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
_update_min_padding!(sp)
|
||||
|
||||
# the viewports for this subplot
|
||||
viewport_subplot = gr_viewport_from_bbox(sp, bbox(sp), w, h, viewport_canvas)
|
||||
viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas)
|
||||
# get data limits
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
xy_lims = data_lims
|
||||
|
||||
ratio = sp[:aspect_ratio]
|
||||
if ratio != :none
|
||||
@@ -573,27 +674,25 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
# reduced from before... set some flags based on the series in this subplot
|
||||
# TODO: can these be generic flags?
|
||||
outside_ticks = false
|
||||
cmap = false
|
||||
draw_axes = true
|
||||
cmap = hascolorbar(sp)
|
||||
draw_axes = sp[:framestyle] != :none
|
||||
# axes_2d = true
|
||||
for series in series_list(sp)
|
||||
st = series[:seriestype]
|
||||
if st in (:contour, :surface, :heatmap) || series[:marker_z] != nothing
|
||||
cmap = true
|
||||
end
|
||||
if st == :pie
|
||||
draw_axes = false
|
||||
end
|
||||
if st == :heatmap
|
||||
outside_ticks = true
|
||||
x, y = heatmap_edges(series[:x]), heatmap_edges(series[:y])
|
||||
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale])
|
||||
xy_lims = x[1], x[end], y[1], y[end]
|
||||
expand_extrema!(sp[:xaxis], x)
|
||||
expand_extrema!(sp[:yaxis], y)
|
||||
data_lims = gr_xy_axislims(sp)
|
||||
end
|
||||
end
|
||||
|
||||
if cmap && sp[:colorbar] != :none
|
||||
if cmap
|
||||
# note: add extra midpadding on the right for the colorbar
|
||||
viewport_plotarea[2] -= 0.1
|
||||
end
|
||||
@@ -651,23 +750,22 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
isfinite(clims[1]) && (zmin = clims[1])
|
||||
isfinite(clims[2]) && (zmax = clims[2])
|
||||
end
|
||||
GR.setspace(zmin, zmax, 40, 70)
|
||||
GR.setspace(zmin, zmax, 35, 60)
|
||||
xtick = GR.tick(xmin, xmax) / 2
|
||||
ytick = GR.tick(ymin, ymax) / 2
|
||||
ztick = GR.tick(zmin, zmax) / 2
|
||||
ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1])
|
||||
|
||||
# GR.setlinetype(GR.LINETYPE_DOTTED)
|
||||
if sp[:grid]
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymax, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
|
||||
end
|
||||
xaxis[:grid] && GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0)
|
||||
yaxis[:grid] && GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
|
||||
zaxis[:grid] && GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2)
|
||||
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
|
||||
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
|
||||
|
||||
elseif ispolar(sp)
|
||||
r = gr_set_viewport_polar()
|
||||
rmin, rmax = GR.adjustrange(ignoreNaN_minimum(r), ignoreNaN_maximum(r))
|
||||
rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
|
||||
# rmin, rmax = axis_limits(sp[:yaxis])
|
||||
gr_polaraxes(rmin, rmax)
|
||||
|
||||
@@ -676,58 +774,85 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.setwindow(xmin, xmax, ymin, ymax)
|
||||
end
|
||||
|
||||
xticks, yticks, spine_segs, grid_segs = axis_drawing_info(sp)
|
||||
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
|
||||
# @show xticks yticks #spine_segs grid_segs
|
||||
|
||||
# draw the grid lines
|
||||
if sp[:grid]
|
||||
if xaxis[:grid]
|
||||
# gr_set_linecolor(sp[:foreground_color_grid])
|
||||
# GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
gr_set_line(1, :dot, sp[:foreground_color_grid])
|
||||
GR.settransparency(0.5)
|
||||
gr_polyline(coords(grid_segs)...)
|
||||
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
|
||||
GR.settransparency(xaxis[:gridalpha])
|
||||
gr_polyline(coords(xgrid_segs)...)
|
||||
end
|
||||
if yaxis[:grid]
|
||||
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
|
||||
GR.settransparency(yaxis[:gridalpha])
|
||||
gr_polyline(coords(ygrid_segs)...)
|
||||
end
|
||||
GR.settransparency(1.0)
|
||||
|
||||
# spine (border) and tick marks
|
||||
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
|
||||
# axis lines
|
||||
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(spine_segs)...)
|
||||
gr_polyline(coords(xspine_segs)...)
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(yspine_segs)...)
|
||||
GR.setclip(1)
|
||||
|
||||
if !(xticks in (nothing, false))
|
||||
# axis ticks
|
||||
if sp[:framestyle] in (:zerolines, :grid)
|
||||
gr_set_line(1, :solid, xaxis[:foreground_color_grid])
|
||||
GR.settransparency(xaxis[:gridalpha])
|
||||
else
|
||||
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
|
||||
end
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(xtick_segs)...)
|
||||
if sp[:framestyle] in (:zerolines, :grid)
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_grid])
|
||||
GR.settransparency(yaxis[:gridalpha])
|
||||
else
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
end
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(ytick_segs)...)
|
||||
GR.setclip(1)
|
||||
|
||||
# tick marks
|
||||
if !(xticks in (:none, nothing, false))
|
||||
# x labels
|
||||
flip = sp[:yaxis][:flip]
|
||||
mirror = sp[:xaxis][:mirror]
|
||||
gr_set_font(sp[:xaxis][:tickfont],
|
||||
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
|
||||
valign = (mirror ? :bottom : :top),
|
||||
color = sp[:xaxis][:foreground_color_axis],
|
||||
rotation = sp[:xaxis][:rotation])
|
||||
flip, mirror = gr_set_xticks_font(sp)
|
||||
for (cv, dv) in zip(xticks...)
|
||||
# use xor ($) to get the right y coords
|
||||
xi, yi = GR.wctondc(cv, (flip $ mirror) ? ymax : ymin)
|
||||
xi, yi = GR.wctondc(cv, sp[:framestyle] == :origin ? 0 : 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))
|
||||
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0), string(dv))
|
||||
end
|
||||
end
|
||||
|
||||
if !(yticks in (nothing, false))
|
||||
if !(yticks in (:none, nothing, false))
|
||||
# y labels
|
||||
flip = sp[:xaxis][:flip]
|
||||
mirror = sp[:yaxis][:mirror]
|
||||
gr_set_font(sp[:yaxis][:tickfont],
|
||||
halign = (mirror ? :left : :right),
|
||||
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
|
||||
color = sp[:yaxis][:foreground_color_axis],
|
||||
rotation = sp[:yaxis][:rotation])
|
||||
flip, mirror = gr_set_yticks_font(sp)
|
||||
for (cv, dv) in zip(yticks...)
|
||||
# use xor ($) to get the right y coords
|
||||
xi, yi = GR.wctondc((flip $ mirror) ? xmax : xmin, cv)
|
||||
xi, yi = GR.wctondc(sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? xmax : xmin, cv)
|
||||
# @show cv dv xmin xi yi
|
||||
gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv))
|
||||
gr_text(xi + (mirror ? 1 : -1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), yi, string(dv))
|
||||
end
|
||||
end
|
||||
|
||||
# border
|
||||
intensity = sp[:framestyle] == :semi ? 0.5 : 1.0
|
||||
if sp[:framestyle] in (:box, :semi)
|
||||
gr_set_line(intensity, :solid, xaxis[:foreground_color_border])
|
||||
GR.settransparency(intensity)
|
||||
gr_polyline(coords(xborder_segs)...)
|
||||
gr_set_line(intensity, :solid, yaxis[:foreground_color_border])
|
||||
GR.settransparency(intensity)
|
||||
gr_polyline(coords(yborder_segs)...)
|
||||
end
|
||||
end
|
||||
# end
|
||||
|
||||
@@ -761,6 +886,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
# this needs to be here to point the colormap to the right indices
|
||||
GR.setcolormap(1000 + GR.COLORMAP_COOLWARM)
|
||||
|
||||
# calculate the colorbar limits once for a subplot
|
||||
clims = get_clims(sp)
|
||||
|
||||
for (idx, series) in enumerate(series_list(sp))
|
||||
st = series[:seriestype]
|
||||
|
||||
@@ -769,6 +897,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
gr_set_gradient(series[:fillcolor]) #, series[:fillalpha])
|
||||
elseif series[:marker_z] != nothing
|
||||
series[:markercolor] = gr_set_gradient(series[:markercolor])
|
||||
elseif series[:line_z] != nothing
|
||||
series[:linecolor] = gr_set_gradient(series[:linecolor])
|
||||
elseif series[:fill_z] != nothing
|
||||
series[:fillcolor] = gr_set_gradient(series[:fillcolor])
|
||||
end
|
||||
|
||||
GR.savestate()
|
||||
@@ -807,36 +939,42 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
if frng != nothing
|
||||
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
|
||||
for i in 1:length(x) - 1
|
||||
gr_set_fillcolor(get_fillcolor(sp, series, i))
|
||||
xseg = _cycle(x, [i, i+1, i+1, i])
|
||||
yseg = [_cycle(fr_from, [i, i+1]); _cycle(fr_to, [i+1, i])]
|
||||
series[:fillalpha] != nothing && GR.settransparency(series[:fillalpha])
|
||||
GR.fillarea(xseg, yseg)
|
||||
end
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
GR.settransparency(1)
|
||||
cmap && gr_colorbar(sp, clims)
|
||||
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)
|
||||
for i in 1:length(x) - 1
|
||||
xseg = x[i:(i + 1)]
|
||||
yseg = y[i:(i + 1)]
|
||||
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
|
||||
arrowside = (i == length(y) - 1) && isa(series[:arrow], Arrow) ? series[:arrow].side : :none
|
||||
gr_polyline(xseg, yseg; arrowside = arrowside)
|
||||
end
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
cmap && gr_colorbar(sp, clims)
|
||||
end
|
||||
end
|
||||
|
||||
if series[:markershape] != :none
|
||||
gr_draw_markers(series, x, y)
|
||||
if series[:marker_z] != nothing
|
||||
zmin, zmax = extrema(series[:marker_z])
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
end
|
||||
gr_draw_markers(series, x, y, clims)
|
||||
end
|
||||
|
||||
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
|
||||
zmin, zmax = clims
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
if typeof(series[:levels]) <: Array
|
||||
h = series[:levels]
|
||||
@@ -850,9 +988,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
end
|
||||
|
||||
# create the colorbar of contour levels
|
||||
if sp[:colorbar] != :none
|
||||
if cmap
|
||||
gr_set_viewport_cmap(sp)
|
||||
l = round(Int32, 1000 + (h - ignoreNaN_minimum(h)) / (ignoreNaN_maximum(h) - ignoreNaN_minimum(h)) * 255)
|
||||
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
|
||||
GR.setwindow(xmin, xmax, zmin, zmax)
|
||||
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
|
||||
ztick = 0.5 * GR.tick(zmin, zmax)
|
||||
@@ -874,12 +1012,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
cmap && gr_colorbar(sp)
|
||||
|
||||
elseif st == :heatmap
|
||||
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
|
||||
xmin, xmax, ymin, ymax = xy_lims
|
||||
zmin, zmax = clims
|
||||
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]
|
||||
@@ -887,22 +1021,28 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
round(Int, blue(c) * 255) << 16 +
|
||||
round(Int, green(c) * 255) << 8 +
|
||||
round(Int, red(c) * 255) ), colors)
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, length(x), length(y), rgba)
|
||||
cmap && gr_colorbar(sp)
|
||||
w, h = length(x), length(y)
|
||||
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
|
||||
cmap && gr_colorbar(sp, clims)
|
||||
|
||||
elseif st in (:path3d, :scatter3d)
|
||||
# draw path
|
||||
if st == :path3d
|
||||
if length(x) > 1
|
||||
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
|
||||
GR.polyline3d(x, y, z)
|
||||
for i in 1:length(x) - 1
|
||||
xseg = x[i:(i + 1)]
|
||||
yseg = y[i:(i + 1)]
|
||||
zseg = z[i:(i + 1)]
|
||||
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
|
||||
GR.polyline3d(xseg, yseg, zseg)
|
||||
end
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
cmap && gr_colorbar(sp, clims)
|
||||
end
|
||||
|
||||
# draw markers
|
||||
if st == :scatter3d || series[:markershape] != :none
|
||||
x2, y2 = unzip(map(GR.wc3towc, x, y, z))
|
||||
gr_draw_markers(series, x2, y2)
|
||||
gr_draw_markers(series, x2, y2, clims)
|
||||
end
|
||||
|
||||
# TODO: replace with pie recipe
|
||||
@@ -954,23 +1094,25 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
GR.selntran(1)
|
||||
|
||||
elseif st == :shape
|
||||
for (i,rng) in enumerate(iter_segments(series[:x], series[:y]))
|
||||
for (i,rng) in enumerate(iter_segments(x, y))
|
||||
if length(rng) > 1
|
||||
# connect to the beginning
|
||||
rng = vcat(rng, rng[1])
|
||||
|
||||
# get the segments
|
||||
x, y = series[:x][rng], series[:y][rng]
|
||||
xseg, yseg = x[rng], y[rng]
|
||||
|
||||
# draw the interior
|
||||
gr_set_fill(cycle(series[:fillcolor], i))
|
||||
GR.fillarea(x, y)
|
||||
gr_set_fill(get_fillcolor(sp, series, i))
|
||||
GR.fillarea(xseg, yseg)
|
||||
|
||||
# draw the shapes
|
||||
gr_set_line(series[:linewidth], :solid, cycle(series[:linecolor], i))
|
||||
GR.polyline(x, y)
|
||||
gr_set_line(series[:linewidth], :solid, get_linecolor(sp, series, i))
|
||||
GR.polyline(xseg, yseg)
|
||||
end
|
||||
end
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
cmap && gr_colorbar(sp, clims)
|
||||
|
||||
|
||||
elseif st == :image
|
||||
@@ -1039,23 +1181,34 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
if sp[:legendtitle] != nothing
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
|
||||
gr_set_textcolor(sp[:foreground_color_legend])
|
||||
GR.settransparency(1)
|
||||
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
|
||||
ypos -= dy
|
||||
end
|
||||
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 == :path && series[:fillrange] == nothing
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
|
||||
elseif st == :shape || series[:fillrange] != nothing
|
||||
gr_set_fill(series[:fillcolor]) #, series[:fillalpha])
|
||||
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series)) #, series[:linealpha])
|
||||
|
||||
if (st == :shape || series[:fillrange] != nothing) && series[:ribbon] == nothing
|
||||
gr_set_fill(get_fillcolor(sp, series)) #, series[:fillalpha])
|
||||
l, r = xpos-0.07, xpos-0.01
|
||||
b, t = ypos-0.4dy, ypos+0.4dy
|
||||
x = [l, r, r, l, l]
|
||||
y = [b, b, t, t, b]
|
||||
GR.settransparency(gr_alpha(series[:fillalpha]))
|
||||
gr_polyline(x, y, GR.fillarea)
|
||||
gr_polyline(x, y)
|
||||
GR.settransparency(gr_alpha(series[:linealpha]))
|
||||
st == :shape && gr_polyline(x, y)
|
||||
end
|
||||
|
||||
if st == :path
|
||||
GR.settransparency(gr_alpha(series[:linealpha]))
|
||||
if series[:fillrange] == nothing || series[:ribbon] != nothing
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
|
||||
else
|
||||
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos+0.4dy, ypos+0.4dy])
|
||||
end
|
||||
end
|
||||
|
||||
if series[:markershape] != :none
|
||||
|
||||
+32
-29
@@ -18,7 +18,8 @@ Add in functionality to Plots.jl:
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
# :foreground_color_grid,
|
||||
:foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
@@ -265,8 +266,8 @@ For st in :shape:
|
||||
nmax = i
|
||||
if length(rng) > 1
|
||||
linewidth = series[:linewidth]
|
||||
linecolor = _inspectdr_mapcolor(cycle(series[:linecolor], i))
|
||||
fillcolor = _inspectdr_mapcolor(cycle(series[:fillcolor], i))
|
||||
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
|
||||
fillcolor = _inspectdr_mapcolor(_cycle(series[:fillcolor], i))
|
||||
line = InspectDR.line(
|
||||
style=:solid, width=linewidth, color=linecolor
|
||||
)
|
||||
@@ -280,8 +281,8 @@ For st in :shape:
|
||||
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))
|
||||
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
|
||||
@@ -334,15 +335,18 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
const gridon = InspectDR.GridRect(vmajor=true, hmajor=true)
|
||||
const gridoff = InspectDR.GridRect()
|
||||
const plot = sp.o
|
||||
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
|
||||
|
||||
#No independent control of grid???
|
||||
strip.grid = sp[:grid]? gridon: gridoff
|
||||
|
||||
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
|
||||
xgrid_show = xaxis[:grid]
|
||||
ygrid_show = yaxis[:grid]
|
||||
|
||||
strip.grid = InspectDR.GridRect(
|
||||
vmajor=xgrid_show, # vminor=xgrid_show,
|
||||
hmajor=ygrid_show, # hminor=ygrid_show,
|
||||
)
|
||||
|
||||
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
|
||||
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
|
||||
xmin, xmax = axis_limits(xaxis)
|
||||
@@ -362,30 +366,29 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
|
||||
|
||||
l = plot.layout
|
||||
l.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l.framedata.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l.framedata.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l.fnttitle = InspectDR.Font(sp[:titlefont].family,
|
||||
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
|
||||
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
|
||||
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
|
||||
l[:font_title] = InspectDR.Font(sp[:titlefont].family,
|
||||
_inspectdr_mapptsize(sp[:titlefont].pointsize),
|
||||
color = _inspectdr_mapcolor(sp[:foreground_color_title])
|
||||
)
|
||||
#Cannot independently control fonts of axes with InspectDR:
|
||||
l.fntaxlabel = InspectDR.Font(xaxis[:guidefont].family,
|
||||
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefont].family,
|
||||
_inspectdr_mapptsize(xaxis[:guidefont].pointsize),
|
||||
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide])
|
||||
)
|
||||
l.fntticklabel = InspectDR.Font(xaxis[:tickfont].family,
|
||||
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfont].family,
|
||||
_inspectdr_mapptsize(xaxis[:tickfont].pointsize),
|
||||
color = _inspectdr_mapcolor(xaxis[:foreground_color_text])
|
||||
)
|
||||
leg = l.legend
|
||||
leg.enabled = (sp[:legend] != :none)
|
||||
#leg.width = 150 #TODO: compute???
|
||||
leg.font = InspectDR.Font(sp[:legendfont].family,
|
||||
l[:enable_legend] = (sp[:legend] != :none)
|
||||
#l[:halloc_legend] = 150 #TODO: compute???
|
||||
l[:font_legend] = InspectDR.Font(sp[:legendfont].family,
|
||||
_inspectdr_mapptsize(sp[:legendfont].pointsize),
|
||||
color = _inspectdr_mapcolor(sp[:foreground_color_legend])
|
||||
)
|
||||
leg.frame.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
|
||||
end
|
||||
|
||||
# called just before updating layout bounding boxes... in case you need to prep
|
||||
@@ -399,7 +402,7 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
#Don't use window_title... probably not what you want.
|
||||
#mplot.title = plt[:window_title]
|
||||
end
|
||||
mplot.frame.fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
|
||||
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
|
||||
|
||||
resize!(mplot.subplots, length(plt.subplots))
|
||||
nsubplots = length(plt.subplots)
|
||||
@@ -421,15 +424,15 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
|
||||
#Do not yet support absolute plot positionning.
|
||||
#Just try to make things look more-or less ok:
|
||||
if nsubplots <= 1
|
||||
mplot.ncolumns = 1
|
||||
mplot.layout[:ncolumns] = 1
|
||||
elseif nsubplots <= 4
|
||||
mplot.ncolumns = 2
|
||||
mplot.layout[:ncolumns] = 2
|
||||
elseif nsubplots <= 6
|
||||
mplot.ncolumns = 3
|
||||
mplot.layout[:ncolumns] = 3
|
||||
elseif nsubplots <= 12
|
||||
mplot.ncolumns = 4
|
||||
mplot.layout[:ncolumns] = 4
|
||||
else
|
||||
mplot.ncolumns = 5
|
||||
mplot.layout[:ncolumns] = 5
|
||||
end
|
||||
|
||||
for series in plt.series_list
|
||||
@@ -446,7 +449,7 @@ function _update_min_padding!(sp::Subplot{InspectDRBackend})
|
||||
plot = sp.o
|
||||
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
|
||||
#Computing plotbounds with 0-BoundingBox returns required padding:
|
||||
bb = InspectDR.plotbounds(plot.layout, InspectDR.BoundingBox(0,0,0,0))
|
||||
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
|
||||
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
|
||||
#TODO: possibly zero-out items not in use??
|
||||
|
||||
@@ -468,7 +471,7 @@ function _update_plot_object(plt::Plot{InspectDRBackend})
|
||||
for (i, sp) in enumerate(plt.subplots)
|
||||
graphbb = _inspectdr_to_pixels(plotarea(sp))
|
||||
plot = mplot.subplots[i]
|
||||
plot.plotbb = InspectDR.plotbounds(plot.layout, graphbb)
|
||||
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
|
||||
end
|
||||
|
||||
gplot = _inspectdr_getgui(plt.o)
|
||||
|
||||
@@ -31,6 +31,7 @@ const _pgfplots_attr = merge_with_base_supported([
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
:tick_direction,
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
@@ -98,7 +99,7 @@ const _pgf_series_extrastyle = KW(
|
||||
:xsticks => "xcomb",
|
||||
)
|
||||
|
||||
# PGFPlots uses the anchors to define orientations for example to align left
|
||||
# PGFPlots uses the anchors to define orientations for example to align left
|
||||
# one needs to use the right edge as anchor
|
||||
const _pgf_annotation_halign = KW(
|
||||
:center => "",
|
||||
@@ -121,7 +122,7 @@ function pgf_color(grad::ColorGradient)
|
||||
end
|
||||
|
||||
# Generates a colormap for pgfplots based on a ColorGradient
|
||||
function pgf_colormap(grad::ColorGradient)
|
||||
function pgf_colormap(grad::ColorGradient)
|
||||
join(map(grad.colors) do c
|
||||
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
|
||||
end,", ")
|
||||
@@ -266,6 +267,11 @@ function pgf_axis(sp::Subplot, letter)
|
||||
push!(style, "$(letter)majorticks=false")
|
||||
end
|
||||
|
||||
# grid on or off
|
||||
if axis[:grid]
|
||||
push!(style, "$(letter)majorgrids = true")
|
||||
end
|
||||
|
||||
# limits
|
||||
# TODO: support zlims
|
||||
if letter != :z
|
||||
@@ -274,10 +280,11 @@ function pgf_axis(sp::Subplot, letter)
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :auto))
|
||||
if !(axis[:ticks] in (nothing, false, :none))
|
||||
ticks = get_ticks(axis)
|
||||
push!(style, string(letter, "tick = {", join(ticks[1],","), "}"))
|
||||
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}"))
|
||||
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
@@ -324,7 +331,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
kw[:title] = "$(sp[:title])"
|
||||
end
|
||||
|
||||
sp[:grid] && push!(style, "grid = major")
|
||||
if sp[:aspect_ratio] in (1, :equal)
|
||||
kw[:axisEqual] = "true"
|
||||
end
|
||||
@@ -360,7 +366,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
||||
kw[:colorbar] = "true"
|
||||
end
|
||||
# goto is needed to break out of col and series for
|
||||
@goto colorbar_end
|
||||
@goto colorbar_end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+80
-19
@@ -5,7 +5,7 @@ const _plotly_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
# :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:foreground_color_title,
|
||||
:label,
|
||||
@@ -19,7 +19,8 @@ const _plotly_attr = merge_with_base_supported([
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar, :colorbar_title,
|
||||
:grid, :gridalpha, :gridlinewidth,
|
||||
:legend, :colorbar, :colorbar_title,
|
||||
:marker_z, :fill_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
@@ -32,6 +33,8 @@ const _plotly_attr = merge_with_base_supported([
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:clims,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
])
|
||||
|
||||
const _plotly_seriestype = [
|
||||
@@ -46,6 +49,17 @@ const _plotly_marker = [
|
||||
const _plotly_scale = [:identity, :log10]
|
||||
is_subplot_supported(::PlotlyBackend) = true
|
||||
# is_string_supported(::PlotlyBackend) = true
|
||||
const _plotly_framestyles = [:box, :axes, :zerolines, :grid, :none]
|
||||
const _plotly_framestyle_defaults = Dict(:semi => :box, :origin => :zerolines)
|
||||
function _plotly_framestyle(style::Symbol)
|
||||
if style in _plotly_framestyles
|
||||
return style
|
||||
else
|
||||
default_style = get(_plotly_framestyle_defaults, style, :axes)
|
||||
warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
|
||||
default_style
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -211,11 +225,19 @@ end
|
||||
|
||||
function plotly_axis(axis::Axis, sp::Subplot)
|
||||
letter = axis[:letter]
|
||||
framestyle = sp[:framestyle]
|
||||
ax = KW(
|
||||
:visible => framestyle != :none,
|
||||
:title => axis[:guide],
|
||||
:showgrid => sp[:grid],
|
||||
:zeroline => false,
|
||||
:ticks => "inside",
|
||||
:showgrid => axis[:grid],
|
||||
:gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
|
||||
:gridwidth => axis[:gridlinewidth],
|
||||
:zeroline => framestyle == :zerolines,
|
||||
:zerolinecolor => rgba_string(axis[:foreground_color_axis]),
|
||||
:showline => framestyle in (:box, :axes),
|
||||
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
|
||||
:ticks => axis[:tick_direction] == :out ? "outside" : "inside",
|
||||
:mirror => framestyle == :box,
|
||||
)
|
||||
|
||||
if letter in (:x,:y)
|
||||
@@ -229,8 +251,8 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
|
||||
ax[:type] = plotly_scale(axis[:scale])
|
||||
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
|
||||
ax[:tickcolor] = rgba_string(axis[:foreground_color_border])
|
||||
ax[:linecolor] = rgba_string(axis[:foreground_color_border])
|
||||
ax[:tickcolor] = framestyle in (:zerolines, :grid) ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
|
||||
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
|
||||
|
||||
# lims
|
||||
lims = axis[:lims]
|
||||
@@ -296,6 +318,9 @@ function plotly_layout(plt::Plot)
|
||||
|
||||
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
|
||||
|
||||
# set to supported framestyle
|
||||
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
|
||||
|
||||
# if any(is3d, seriesargs)
|
||||
if is3d(sp)
|
||||
d_out[:scene] = KW(
|
||||
@@ -435,6 +460,8 @@ function plotly_series(plt::Plot, series::Series)
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || series[:markershape] != :none
|
||||
hasline = st in (:path, :path3d)
|
||||
hasfillrange = st in (:path, :scatter, :scattergl) &&
|
||||
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
|
||||
|
||||
# for surface types, set the data
|
||||
if st in (:heatmap, :contour, :surface, :wireframe)
|
||||
@@ -458,11 +485,14 @@ function plotly_series(plt::Plot, series::Series)
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
if series[:fillrange] == true || series[:fillrange] == 0
|
||||
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
|
||||
d_out[:fill] = "tozeroy"
|
||||
d_out[:fillcolor] = rgba_string(series[:fillcolor])
|
||||
elseif isa(series[:fillrange], AbstractVector)
|
||||
d_out[:fill] = "tonexty"
|
||||
d_out[:fillcolor] = rgba_string(series[:fillcolor])
|
||||
elseif !(series[:fillrange] in (false, nothing))
|
||||
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(series[:fillrange])")
|
||||
warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
@@ -479,6 +509,7 @@ function plotly_series(plt::Plot, series::Series)
|
||||
d_out[:type] = "heatmap"
|
||||
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
|
||||
elseif st == :contour
|
||||
d_out[:type] = "contour"
|
||||
@@ -487,6 +518,7 @@ function plotly_series(plt::Plot, series::Series)
|
||||
d_out[:ncontours] = series[:levels]
|
||||
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
|
||||
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
d_out[:type] = "surface"
|
||||
@@ -499,11 +531,14 @@ function plotly_series(plt::Plot, series::Series)
|
||||
:highlightwidth => series[:linewidth],
|
||||
)
|
||||
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
|
||||
d_out[:showscale] = false
|
||||
else
|
||||
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
|
||||
d_out[:opacity] = series[:fillalpha]
|
||||
if series[:fill_z] != nothing
|
||||
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
|
||||
end
|
||||
d_out[:showscale] = sp[:legend] != :none
|
||||
end
|
||||
|
||||
elseif st == :pie
|
||||
@@ -541,14 +576,18 @@ function plotly_series(plt::Plot, series::Series)
|
||||
)
|
||||
|
||||
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
|
||||
d_out[:marker][:color] = if series[:marker_z] == nothing
|
||||
rgba_string(series[:markercolor])
|
||||
if series[:marker_z] == nothing
|
||||
d_out[:marker][:color] = 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 = as_gradient(series[:markercolor], series[:markeralpha])
|
||||
cmin, cmax = get_clims(sp)
|
||||
# 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)
|
||||
d_out[:marker][:color] = [clamp(zi, cmin, cmax) for zi in series[:marker_z]]
|
||||
d_out[:marker][:cmin] = cmin
|
||||
d_out[:marker][:cmax] = cmax
|
||||
d_out[:marker][:colorscale] = plotly_colorscale(series[:markercolor], series[:markeralpha])
|
||||
d_out[:marker][:showscale] = hascolorbar(sp)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -572,7 +611,29 @@ function plotly_series(plt::Plot, series::Series)
|
||||
plotly_polar!(d_out, series)
|
||||
plotly_hover!(d_out, series[:hover])
|
||||
|
||||
[d_out]
|
||||
if hasfillrange
|
||||
# if hasfillrange is true, return two dictionaries (one for original
|
||||
# series, one for series being filled to) instead of one
|
||||
d_out_fillrange = deepcopy(d_out)
|
||||
d_out_fillrange[:showlegend] = false
|
||||
if isa(series[:fillrange], AbstractVector)
|
||||
d_out_fillrange[:y] = series[:fillrange]
|
||||
delete!(d_out_fillrange, :fill)
|
||||
delete!(d_out_fillrange, :fillcolor)
|
||||
else
|
||||
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
|
||||
# is the series that will do the filling
|
||||
d_out_fillrange[:x], d_out_fillrange[:y] =
|
||||
concatenate_fillrange(series[:x], series[:fillrange])
|
||||
d_out_fillrange[:line][:width] = 0
|
||||
delete!(d_out, :fill)
|
||||
delete!(d_out, :fillcolor)
|
||||
end
|
||||
|
||||
return [d_out_fillrange, d_out]
|
||||
else
|
||||
return [d_out]
|
||||
end
|
||||
end
|
||||
|
||||
function plotly_series_shapes(plt::Plot, series::Series)
|
||||
@@ -600,18 +661,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
|
||||
|
||||
+142
-127
@@ -17,7 +17,8 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :legendtitle, :colorbar,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
@@ -31,6 +32,9 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
:stride,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
:path, :steppre, :steppost, :shape,
|
||||
@@ -70,18 +74,26 @@ function _initialize_backend(::PyPlotBackend)
|
||||
append!(Base.Multimedia.displays, otherdisplays)
|
||||
|
||||
export PyPlot
|
||||
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
|
||||
const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
|
||||
const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
|
||||
const pypatches = PyPlot.pywrap(PyPlot.pyimport("matplotlib.patches"))
|
||||
const pyfont = PyPlot.pywrap(PyPlot.pyimport("matplotlib.font_manager"))
|
||||
const pyticker = PyPlot.pywrap(PyPlot.pyimport("matplotlib.ticker"))
|
||||
const pycmap = PyPlot.pywrap(PyPlot.pyimport("matplotlib.cm"))
|
||||
const pynp = PyPlot.pywrap(PyPlot.pyimport("numpy"))
|
||||
pynp.seterr(invalid="ignore")
|
||||
const pytransforms = PyPlot.pywrap(PyPlot.pyimport("matplotlib.transforms"))
|
||||
const pycollections = PyPlot.pywrap(PyPlot.pyimport("matplotlib.collections"))
|
||||
const pyart3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d.art3d"))
|
||||
const pycolors = PyPlot.pyimport("matplotlib.colors")
|
||||
const pypath = PyPlot.pyimport("matplotlib.path")
|
||||
const mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
|
||||
const pypatches = PyPlot.pyimport("matplotlib.patches")
|
||||
const pyfont = PyPlot.pyimport("matplotlib.font_manager")
|
||||
const pyticker = PyPlot.pyimport("matplotlib.ticker")
|
||||
const pycmap = PyPlot.pyimport("matplotlib.cm")
|
||||
const pynp = PyPlot.pyimport("numpy")
|
||||
pynp["seterr"](invalid="ignore")
|
||||
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
|
||||
const pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
const pyart3d = PyPlot.pyimport("mpl_toolkits.mplot3d.art3d")
|
||||
|
||||
# "support" matplotlib v1.5
|
||||
const set_facecolor_sym = if PyPlot.version < v"2"
|
||||
warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0")
|
||||
:set_axis_bgcolor
|
||||
else
|
||||
:set_facecolor
|
||||
end
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
@@ -101,7 +113,7 @@ end
|
||||
|
||||
# function py_colormap(c::ColorGradient, α=nothing)
|
||||
# pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values]
|
||||
# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
|
||||
# pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
# end
|
||||
|
||||
# # convert vectors and ColorVectors to standard ColorGradients
|
||||
@@ -118,7 +130,7 @@ py_color(grad::ColorGradient) = py_color(grad.colors)
|
||||
|
||||
function py_colormap(grad::ColorGradient)
|
||||
pyvals = [(z, py_color(grad[z])) for z in grad.values]
|
||||
cm = pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals)
|
||||
cm = pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
cm[:set_bad](color=(0,0,0,0.0), alpha=0.0)
|
||||
cm
|
||||
end
|
||||
@@ -127,7 +139,7 @@ py_colormap(c) = py_colormap(cgrad())
|
||||
|
||||
function py_shading(c, z)
|
||||
cmap = py_colormap(c)
|
||||
ls = pycolors.pymember("LightSource")(270,45)
|
||||
ls = pycolors["LightSource"](270,45)
|
||||
ls[:shade](z, cmap, vert_exag=0.1, blend_mode="soft")
|
||||
end
|
||||
|
||||
@@ -151,7 +163,7 @@ function py_marker(marker::Shape)
|
||||
mat[i,2] = y[i]
|
||||
end
|
||||
mat[n+1,:] = mat[1,:]
|
||||
pypath.pymember("Path")(mat)
|
||||
pypath["Path"](mat)
|
||||
end
|
||||
|
||||
const _path_MOVETO = UInt8(1)
|
||||
@@ -177,7 +189,7 @@ const _path_CLOSEPOLY = UInt8(79)
|
||||
# lastnan = nan
|
||||
# end
|
||||
# codes[n+1] = _path_CLOSEPOLY
|
||||
# pypath.pymember("Path")(mat, codes)
|
||||
# pypath["Path"](mat, codes)
|
||||
# end
|
||||
|
||||
# get the marker shape
|
||||
@@ -227,14 +239,14 @@ end
|
||||
|
||||
# # untested... return a FontProperties object from a Plots.Font
|
||||
# function py_font(font::Font)
|
||||
# pyfont.pymember("FontProperties")(
|
||||
# pyfont["FontProperties"](
|
||||
# family = font.family,
|
||||
# size = font.size
|
||||
# )
|
||||
# end
|
||||
|
||||
function get_locator_and_formatter(vals::AVec)
|
||||
pyticker.pymember("FixedLocator")(1:length(vals)), pyticker.pymember("FixedFormatter")(vals)
|
||||
pyticker["FixedLocator"](1:length(vals)), pyticker["FixedFormatter"](vals)
|
||||
end
|
||||
|
||||
function add_pyfixedformatter(cbar, vals::AVec)
|
||||
@@ -256,9 +268,9 @@ function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
end
|
||||
|
||||
function py_mask_nans(z)
|
||||
# PyPlot.pywrap(pynp.ma[:masked_invalid](PyPlot.pywrap(z)))
|
||||
PyCall.pycall(pynp.ma[:masked_invalid], Any, z)
|
||||
# pynp.ma[:masked_where](pynp.isnan(z),z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -433,11 +445,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
xyargs = (st in _3dTypes ? (x,y,z) : (x,y))
|
||||
|
||||
# handle zcolor and get c/cmap
|
||||
extrakw = KW()
|
||||
needs_colorbar = hascolorbar(sp)
|
||||
extrakw = if needs_colorbar || is_2tuple(sp[:clims])
|
||||
vmin, vmax = get_clims(sp)
|
||||
KW(:vmin => vmin, :vmax => vmax)
|
||||
else
|
||||
KW()
|
||||
end
|
||||
|
||||
# holds references to any python object representing the matplotlib series
|
||||
handles = []
|
||||
needs_colorbar = false
|
||||
discrete_colorbar_values = nothing
|
||||
|
||||
|
||||
@@ -484,41 +501,36 @@ 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...)
|
||||
if needs_colorbar
|
||||
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
|
||||
end
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
end
|
||||
|
||||
a = series[:arrow]
|
||||
@@ -552,18 +564,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
if series[:markershape] != :none && st in (:path, :scatter, :path3d,
|
||||
:scatter3d, :steppre, :steppost,
|
||||
:bar)
|
||||
extrakw = KW()
|
||||
if series[:marker_z] == nothing
|
||||
extrakw[:c] = py_color_fix(py_markercolor(series), x)
|
||||
else
|
||||
extrakw[:c] = convert(Vector{Float64}, series[:marker_z])
|
||||
extrakw[:cmap] = py_markercolormap(series)
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
needs_colorbar = true
|
||||
end
|
||||
xyargs = if st == :bar && !isvertical(series)
|
||||
(y, x)
|
||||
@@ -581,16 +586,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::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)
|
||||
py_color_fix(py_color(_cycle(series[:markercolor],i)), x)
|
||||
else
|
||||
extrakw[:c]
|
||||
end
|
||||
|
||||
push!(handle, ax[:scatter](cycle(x,i), cycle(y,i);
|
||||
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),
|
||||
marker = py_marker(_cycle(shapes,i)),
|
||||
s = py_dpi_scale(plt, _cycle(series[:markersize],i) .^ 2),
|
||||
edgecolors = msc,
|
||||
linewidths = lw,
|
||||
extrakw...
|
||||
@@ -613,11 +618,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :hexbin
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
handle = ax[:hexbin](x, y;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
@@ -628,18 +628,10 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
end
|
||||
|
||||
if st in (:contour, :contour3d)
|
||||
z = transpose_z(series, z.surf)
|
||||
needs_colorbar = true
|
||||
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
|
||||
if st == :contour3d
|
||||
extrakw[:extend3d] = true
|
||||
@@ -677,11 +669,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
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))
|
||||
@@ -689,13 +676,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
else
|
||||
extrakw[:cmap] = py_fillcolormap(series)
|
||||
end
|
||||
needs_colorbar = true
|
||||
end
|
||||
handle = ax[st == :surface ? :plot_surface : :plot_wireframe](x, y, z;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
rstride = 1,
|
||||
cstride = 1,
|
||||
rstride = series[:stride][1],
|
||||
cstride = series[:stride][2],
|
||||
linewidth = py_dpi_scale(plt, series[:linewidth]),
|
||||
edgecolor = py_linecolor(series),
|
||||
extrakw...
|
||||
@@ -705,21 +691,16 @@ 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" ? ignorenan_maximum : ignorenan_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" ? ignorenan_maximum : ignorenan_minimum)(mat) # where to draw the contour plane
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
end
|
||||
end
|
||||
|
||||
# no colorbar if we are creating a surface LightSource
|
||||
if haskey(extrakw, :facecolors)
|
||||
needs_colorbar = false
|
||||
end
|
||||
|
||||
elseif typeof(z) <: AbstractVector
|
||||
# tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots)
|
||||
@@ -737,7 +718,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
else
|
||||
error("Unsupported z type $(typeof(z)) for seriestype=$st")
|
||||
end
|
||||
@@ -768,7 +748,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :heatmap
|
||||
x, y, z = heatmap_edges(x), heatmap_edges(y), transpose_z(series, z.surf)
|
||||
x, y, z = heatmap_edges(x, sp[:xaxis][:scale]), heatmap_edges(y, sp[:yaxis][:scale]), transpose_z(series, z.surf)
|
||||
|
||||
expand_extrema!(sp[:xaxis], x)
|
||||
expand_extrema!(sp[:yaxis], y)
|
||||
@@ -777,11 +757,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
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);
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
@@ -790,20 +765,19 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
end
|
||||
|
||||
if st == :shape
|
||||
handle = []
|
||||
for (i,rng) in enumerate(iter_segments(x, y))
|
||||
if length(rng) > 1
|
||||
path = pypath.pymember("Path")(hcat(x[rng], y[rng]))
|
||||
patches = pypatches.pymember("PathPatch")(
|
||||
path = pypath["Path"](hcat(x[rng], y[rng]))
|
||||
patches = pypatches["PathPatch"](
|
||||
path;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
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
|
||||
)
|
||||
@@ -833,30 +807,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# # smoothing
|
||||
# handleSmooth(plt, ax, series, series[:smooth])
|
||||
|
||||
# add the colorbar legend
|
||||
if needs_colorbar && sp[:colorbar] != :none
|
||||
# add keyword args for a discrete colorbar
|
||||
handle = handles[end]
|
||||
kw = KW()
|
||||
if discrete_colorbar_values != nothing
|
||||
locator, formatter = get_locator_and_formatter(discrete_colorbar_values)
|
||||
# kw[:values] = 1:length(discrete_colorbar_values)
|
||||
kw[:values] = sp[:zaxis][:continuous_values]
|
||||
kw[:ticks] = locator
|
||||
kw[:format] = formatter
|
||||
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
|
||||
end
|
||||
|
||||
# create and store the colorbar object (handle) and the axis that it is drawn on.
|
||||
# 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_ax] = cbax
|
||||
end
|
||||
|
||||
# handle area filling
|
||||
fillrange = series[:fillrange]
|
||||
if fillrange != nothing && st != :contour
|
||||
@@ -926,7 +876,7 @@ function py_compute_axis_minval(axis::Axis)
|
||||
for series in series_list(sp)
|
||||
v = series.d[axis[:letter]]
|
||||
if !isempty(v)
|
||||
minval = NaNMath.min(minval, ignoreNaN_minimum(abs(v)))
|
||||
minval = NaNMath.min(minval, ignorenan_minimum(abs.(v)))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -954,21 +904,22 @@ 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)] = NaNMath.min(1e-16, py_compute_axis_minval(axis))
|
||||
"symlog"
|
||||
end
|
||||
func(arg; kw...)
|
||||
end
|
||||
|
||||
|
||||
function py_set_axis_colors(ax, a::Axis)
|
||||
function py_set_axis_colors(sp, ax, a::Axis)
|
||||
for (loc, spine) in ax[:spines]
|
||||
spine[:set_color](py_color(a[:foreground_color_border]))
|
||||
end
|
||||
axissym = Symbol(a[:letter], :axis)
|
||||
if haskey(ax, axissym)
|
||||
tickcolor = sp[:framestyle] == :zerolines ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis])
|
||||
ax[:tick_params](axis=string(a[:letter]), which="both",
|
||||
colors=py_color(a[:foreground_color_axis]),
|
||||
colors=tickcolor,
|
||||
labelcolor=py_color(a[:foreground_color_text]))
|
||||
ax[axissym][:label][:set_color](py_color(a[:foreground_color_guide]))
|
||||
end
|
||||
@@ -985,7 +936,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
fig[:clear]()
|
||||
dpi = plt[:dpi]
|
||||
fig[:set_size_inches](w/dpi, h/dpi, forward = true)
|
||||
fig[:set_facecolor](py_color(plt[:background_color_outside]))
|
||||
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
|
||||
fig[:set_dpi](dpi)
|
||||
|
||||
# resize the window
|
||||
@@ -1030,6 +981,58 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
# ax[:set_title](sp[:title], loc = loc)
|
||||
end
|
||||
|
||||
# add the colorbar legend
|
||||
if hascolorbar(sp)
|
||||
# add keyword args for a discrete colorbar
|
||||
slist = series_list(sp)
|
||||
colorbar_series = slist[findfirst(hascolorbar.(slist))]
|
||||
handle = colorbar_series[:serieshandle][end]
|
||||
kw = KW()
|
||||
if !isempty(sp[:zaxis][:discrete_values]) && colorbar_series[:seriestype] == :heatmap
|
||||
locator, formatter = get_locator_and_formatter(sp[:zaxis][:discrete_values])
|
||||
# kw[:values] = 1:length(sp[:zaxis][:discrete_values])
|
||||
kw[:values] = sp[:zaxis][:continuous_values]
|
||||
kw[:ticks] = locator
|
||||
kw[:format] = formatter
|
||||
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
|
||||
end
|
||||
|
||||
# create and store the colorbar object (handle) and the axis that it is drawn on.
|
||||
# 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_ax] = cbax
|
||||
end
|
||||
|
||||
# framestyle
|
||||
if !ispolar(sp) && !is3d(sp)
|
||||
if sp[:framestyle] == :semi
|
||||
intensity = 0.5
|
||||
ax[:spines]["right"][:set_alpha](intensity)
|
||||
ax[:spines]["top"][:set_alpha](intensity)
|
||||
ax[:spines]["right"][:set_linewidth](intensity)
|
||||
ax[:spines]["top"][:set_linewidth](intensity)
|
||||
elseif sp[:framestyle] in (:axes, :origin)
|
||||
ax[:spines]["right"][:set_visible](false)
|
||||
ax[:spines]["top"][:set_visible](false)
|
||||
if sp[:framestyle] == :origin
|
||||
ax[:spines]["bottom"][:set_position]("zero")
|
||||
ax[:spines]["left"][:set_position]("zero")
|
||||
end
|
||||
elseif sp[:framestyle] in (:grid, :none, :zerolines)
|
||||
for (loc, spine) in ax[:spines]
|
||||
spine[:set_visible](false)
|
||||
end
|
||||
if sp[:framestyle] == :zerolines
|
||||
ax[:axhline](y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = 0.75)
|
||||
ax[:axvline](x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = 0.75)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# axis attributes
|
||||
for letter in (:x, :y, :z)
|
||||
axissym = Symbol(letter, :axis)
|
||||
@@ -1044,7 +1047,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
py_set_scale(ax, axis)
|
||||
py_set_lims(ax, axis)
|
||||
py_set_ticks(ax, get_ticks(axis), letter)
|
||||
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && length(ticks) > 1
|
||||
ticks[2][ticks[1] .== 0] = ""
|
||||
end
|
||||
py_set_ticks(ax, ticks, letter)
|
||||
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
|
||||
ax[Symbol("set_", letter, "label")](axis[:guide])
|
||||
if get(axis.d, :flip, false)
|
||||
ax[Symbol("invert_", letter, "axis")]()
|
||||
@@ -1056,12 +1065,16 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
lab[:set_family](axis[:tickfont].family)
|
||||
lab[:set_rotation](axis[:rotation])
|
||||
end
|
||||
if sp[:grid]
|
||||
fgcolor = py_color(sp[:foreground_color_grid])
|
||||
pyaxis[:grid](true, color = fgcolor, linestyle = ":")
|
||||
if axis[:grid] && !(ticks in (:none, nothing, false))
|
||||
fgcolor = py_color(axis[:foreground_color_grid])
|
||||
pyaxis[:grid](true,
|
||||
color = fgcolor,
|
||||
linestyle = py_linestyle(:line, axis[:gridstyle]),
|
||||
linewidth = axis[:gridlinewidth],
|
||||
alpha = axis[:gridalpha])
|
||||
ax[:set_axisbelow](true)
|
||||
end
|
||||
py_set_axis_colors(ax, axis)
|
||||
py_set_axis_colors(sp, ax, axis)
|
||||
end
|
||||
|
||||
# aspect ratio
|
||||
@@ -1074,7 +1087,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
py_add_legend(plt, sp, ax)
|
||||
|
||||
# this sets the bg color inside the grid
|
||||
ax[:set_facecolor](py_color(sp[:background_color_inside]))
|
||||
ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
|
||||
|
||||
end
|
||||
py_drawfig(fig)
|
||||
end
|
||||
@@ -1166,7 +1180,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
|
||||
@@ -1196,7 +1210,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
|
||||
# set some legend properties
|
||||
frame = leg[:get_frame]()
|
||||
frame[:set_facecolor](py_color(sp[:background_color_legend]))
|
||||
frame[set_facecolor_sym](py_color(sp[:background_color_legend]))
|
||||
frame[:set_edgecolor](fgcolor)
|
||||
end
|
||||
end
|
||||
@@ -1220,7 +1234,8 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
|
||||
if haskey(sp.attr, :cbar_ax)
|
||||
cbw = sp.attr[:cbar_width]
|
||||
# this is the bounding box of just the colors of the colorbar (not labels)
|
||||
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox)+2mm, _cbar_width-1mm, height(sp.bbox)-4mm)
|
||||
has_toplabel = sp[:zaxis][:extrema].emax >= 1e7
|
||||
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox) + (has_toplabel ? 4mm : 2mm), _cbar_width-1mm, height(sp.bbox) - (has_toplabel ? 6mm : 4mm))
|
||||
pcts = bbox_to_pcts(cb_bbox, figw, figh)
|
||||
sp.attr[:cbar_ax][:set_position](pcts)
|
||||
end
|
||||
|
||||
+56
-8
@@ -22,6 +22,13 @@ immutable Shape
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
"""
|
||||
Shape(x, y)
|
||||
Shape(vertices)
|
||||
|
||||
Construct a polygon to be plotted
|
||||
"""
|
||||
Shape(verts::AVec) = Shape(unzip(verts)...)
|
||||
Shape(s::Shape) = deepcopy(s)
|
||||
|
||||
@@ -32,6 +39,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
|
||||
#deprecated
|
||||
@deprecate shape_coords coords
|
||||
|
||||
"return the vertex points from a Shape or Segments object"
|
||||
function coords(shape::Shape)
|
||||
shape.x, shape.y
|
||||
end
|
||||
@@ -156,6 +164,7 @@ Shape(k::Symbol) = deepcopy(_shapes[k])
|
||||
|
||||
|
||||
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
|
||||
"return the centroid of a Shape"
|
||||
function center(shape::Shape)
|
||||
x, y = coords(shape)
|
||||
n = length(x)
|
||||
@@ -189,6 +198,7 @@ function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
scale!(shapecopy, x, y, c)
|
||||
end
|
||||
|
||||
"translate a Shape in space"
|
||||
function translate!(shape::Shape, x::Real, y::Real = x)
|
||||
sx, sy = coords(shape)
|
||||
for i=1:length(sx)
|
||||
@@ -227,6 +237,7 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
|
||||
shape
|
||||
end
|
||||
|
||||
"rotate an object in space"
|
||||
function rotate(shape::Shape, Θ::Real, c = center(shape))
|
||||
shapecopy = deepcopy(shape)
|
||||
rotate!(shapecopy, Θ, c)
|
||||
@@ -297,12 +308,33 @@ function scalefontsize(k::Symbol, factor::Number)
|
||||
f.pointsize = round(Int, factor * f.pointsize)
|
||||
default(k, f)
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes(factor::Number)
|
||||
|
||||
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
|
||||
"""
|
||||
function scalefontsizes(factor::Number)
|
||||
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
|
||||
scalefontsize(k, factor)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
scalefontsizes()
|
||||
|
||||
Resets font sizes to initial default values.
|
||||
"""
|
||||
function scalefontsizes()
|
||||
for k in (:titlefont, :guidefont, :tickfont, :legendfont)
|
||||
f = default(k)
|
||||
if k in keys(_initial_fontsizes)
|
||||
factor = f.pointsize / _initial_fontsizes[k]
|
||||
scalefontsize(k, 1.0/factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
"Wrap a string with font info"
|
||||
immutable PlotText
|
||||
str::AbstractString
|
||||
@@ -310,6 +342,11 @@ immutable PlotText
|
||||
end
|
||||
PlotText(str) = PlotText(string(str), font())
|
||||
|
||||
"""
|
||||
text(string, args...)
|
||||
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations
|
||||
"""
|
||||
text(t::PlotText) = t
|
||||
text(str::AbstractString, f::Font) = PlotText(str, f)
|
||||
function text(str, args...)
|
||||
@@ -329,6 +366,11 @@ immutable Stroke
|
||||
style
|
||||
end
|
||||
|
||||
"""
|
||||
stroke(args...; alpha = nothing)
|
||||
|
||||
Define the properties of the stroke used in plotting lines
|
||||
"""
|
||||
function stroke(args...; alpha = nothing)
|
||||
width = 1
|
||||
color = :black
|
||||
@@ -446,7 +488,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
msw,msh = anns.scalefactor
|
||||
msize = Float64[]
|
||||
shapes = Shape[begin
|
||||
str = cycle(anns.strs,i)
|
||||
str = _cycle(anns.strs,i)
|
||||
|
||||
# get the width and height of the string (in mm)
|
||||
sw, sh = text_size(str, anns.font.pointsize)
|
||||
@@ -462,7 +504,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
# 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)
|
||||
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
|
||||
@@ -479,13 +521,13 @@ 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)
|
||||
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)
|
||||
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
|
||||
end
|
||||
|
||||
annotations(::Void) = []
|
||||
@@ -501,13 +543,13 @@ immutable ZValues
|
||||
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} = (ignorenan_minimum(values), ignorenan_maximum(values)))
|
||||
ZValues(collect(float(values)), map(Float64, zrange))
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
abstract AbstractSurface
|
||||
abstract type AbstractSurface end
|
||||
|
||||
"represents a contour or surface mesh"
|
||||
immutable Surface{M<:AMat} <: AbstractSurface
|
||||
@@ -576,6 +618,12 @@ immutable Arrow
|
||||
headwidth::Float64
|
||||
end
|
||||
|
||||
"""
|
||||
arrow(args...)
|
||||
|
||||
Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
|
||||
`side` (`:head`, `:tail` or `:both`), `headlength` and `headwidth`
|
||||
"""
|
||||
function arrow(args...)
|
||||
style = :simple
|
||||
side = :head
|
||||
@@ -631,7 +679,7 @@ immutable Formatted{T}
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"create a BezierCurve for plotting"
|
||||
type BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
@@ -659,7 +707,7 @@ function directed_curve(args...; kw...)
|
||||
end
|
||||
|
||||
function extrema_plus_buffer(v, buffmult = 0.2)
|
||||
vmin,vmax = ignoreNaN_extrema(v)
|
||||
vmin,vmax = ignorenan_extrema(v)
|
||||
vdiff = vmax-vmin
|
||||
buffer = vdiff * buffmult
|
||||
vmin - buffer, vmax + buffer
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
abstract ColorScheme
|
||||
abstract type ColorScheme end
|
||||
|
||||
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
|
||||
|
||||
|
||||
+41
-12
@@ -41,7 +41,7 @@ PlotExample("Colors",
|
||||
[:(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")
|
||||
scatter!(y, zcolor=abs.(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y-0.5)+4, lab="grad")
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -66,8 +66,8 @@ PlotExample("Global",
|
||||
PlotExample("Images",
|
||||
"Plot an image. y-axis is set to flipped",
|
||||
[:(begin
|
||||
import Images
|
||||
img = Images.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
|
||||
import FileIO
|
||||
img = FileIO.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
|
||||
plot(img)
|
||||
end)]
|
||||
),
|
||||
@@ -119,17 +119,18 @@ PlotExample("Line styles",
|
||||
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
|
||||
n = length(styles)
|
||||
y = cumsum(randn(20,n),1)
|
||||
plot(y, line = (5, styles), label = map(string,styles))
|
||||
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Marker types",
|
||||
"",
|
||||
[:(begin
|
||||
markers = filter(m -> m in Plots.supported_markers(), Plots._shape_keys)'
|
||||
markers = filter(m -> m in Plots.supported_markers(), Plots._shape_keys)
|
||||
markers = reshape(markers, 1, length(markers))
|
||||
n = length(markers)
|
||||
x = linspace(0,10,n+2)[2:end-1]
|
||||
y = repmat(reverse(x)', n, 1)
|
||||
y = repmat(reshape(reverse(x),1,:), n, 1)
|
||||
scatter(x, y, m=(8,:auto), lab=map(string,markers), bg=:linen, xlim=(0,10), ylim=(0,10))
|
||||
end)]
|
||||
),
|
||||
@@ -154,7 +155,7 @@ PlotExample("Subplots",
|
||||
""",
|
||||
[:(begin
|
||||
l = @layout([a{0.1h}; b [c;d e]])
|
||||
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=false)
|
||||
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=:none)
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -215,7 +216,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(x', length(y), 1)
|
||||
X = repmat(reshape(x,1,:), length(y), 1)
|
||||
Y = repmat(y, 1, length(x))
|
||||
Z = map(f, X, Y)
|
||||
p1 = contour(x, y, f, fill=true)
|
||||
@@ -269,7 +270,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)]
|
||||
),
|
||||
@@ -279,7 +280,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)*(1:10)')
|
||||
z = float((1:4)*reshape(1:10,1,:))
|
||||
heatmap(xs, ys, z, aspect_ratio=1)
|
||||
end)]
|
||||
),
|
||||
@@ -287,9 +288,10 @@ PlotExample("Heatmap, categorical axes, and aspect_ratio",
|
||||
PlotExample("Layouts, margins, label rotation, title location",
|
||||
"",
|
||||
[:(begin
|
||||
using Plots.PlotMeasures # for Measures, e.g. mm and px
|
||||
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
|
||||
title_location=:left, left_margin=[20mm 0mm],
|
||||
bottom_margin=50px, xrotation=60)
|
||||
bottom_margin=10px, xrotation=60)
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -320,7 +322,7 @@ PlotExample("Animation with subplots",
|
||||
),
|
||||
|
||||
PlotExample("Spy",
|
||||
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`",
|
||||
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`.",
|
||||
[:(begin
|
||||
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
|
||||
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
|
||||
@@ -328,6 +330,26 @@ PlotExample("Spy",
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Magic grid argument",
|
||||
"The grid lines can be modified individually for each axis with the magic `grid` argument.",
|
||||
[:(begin
|
||||
x = rand(10)
|
||||
p1 = plot(x, title = "Default looks")
|
||||
p2 = plot(x, grid = (:y, :olivedrab, :dot, 1, 0.9), title = "Modified y grid")
|
||||
p3 = plot(deepcopy(p2), title = "Add x grid")
|
||||
xgrid!(p3, :on, :cadetblue, 2, :dashdot, 0.4)
|
||||
plot(p1, p2, p3, layout = (1, 3), label = "", fillrange = 0, fillalpha = 0.3)
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Framestyle",
|
||||
"The style of the frame/axes of a (sub)plot can be changed with the `framestyle` attribute. The default framestyle is `:axes`.",
|
||||
[:(begin
|
||||
histogram(fill(randn(1000), 5), framestyle = [:box :semi :axes :grid :none],
|
||||
title = [":box" ":semi" ":axes" ":grid" ":none"], color = RowVector(1:5), layout = 5, label = "")
|
||||
end)]
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
@@ -347,6 +369,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
|
||||
end
|
||||
|
||||
# generate all plots and create a dict mapping idx --> plt
|
||||
"""
|
||||
test_examples(pkgname[, idx]; debug = false, disp = true, sleep = nothing,
|
||||
skip = [], only = nothing
|
||||
|
||||
Run the `idx` test example for a given backend, or all examples if `idx`
|
||||
is not specified.
|
||||
"""
|
||||
function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
|
||||
skip = [], only = nothing)
|
||||
Plots._debugMode.on = debug
|
||||
|
||||
+15
-7
@@ -1,16 +1,12 @@
|
||||
|
||||
# NOTE: (0,0) is the top-left !!!
|
||||
|
||||
# allow pixels and percentages
|
||||
const px = AbsoluteLength(0.254)
|
||||
const pct = Length{:pct, Float64}(1.0)
|
||||
|
||||
to_pixels(m::AbsoluteLength) = m.value / 0.254
|
||||
|
||||
const _cbar_width = 5mm
|
||||
|
||||
Base.:.*(m::Measure, n::Number) = m * n
|
||||
Base.:.*(n::Number, m::Measure) = m * n
|
||||
Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
|
||||
Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
|
||||
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
|
||||
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
|
||||
Base.zero(::Type{typeof(mm)}) = 0mm
|
||||
@@ -133,7 +129,12 @@ make_measure_hor(m::Measure) = m
|
||||
make_measure_vert(n::Number) = n * h
|
||||
make_measure_vert(m::Measure) = m
|
||||
|
||||
"""
|
||||
bbox(x, y, w, h [,originargs...])
|
||||
bbox(layout)
|
||||
|
||||
Create a bounding box for plotting
|
||||
"""
|
||||
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
|
||||
oargs = vcat(oarg1, originargs...)
|
||||
orighor = :left
|
||||
@@ -253,6 +254,13 @@ type GridLayout <: AbstractLayout
|
||||
attr::KW
|
||||
end
|
||||
|
||||
"""
|
||||
grid(args...; kw...)
|
||||
|
||||
Create a grid layout for subplots. `args` specify the dimensions, e.g.
|
||||
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two
|
||||
columns of different width.
|
||||
"""
|
||||
grid(args...; kw...) = GridLayout(args...; kw...)
|
||||
|
||||
function GridLayout(dims...;
|
||||
@@ -704,7 +712,7 @@ function link_axes!(axes::Axis...)
|
||||
a1 = axes[1]
|
||||
for i=2:length(axes)
|
||||
a2 = axes[i]
|
||||
expand_extrema!(a1, ignoreNaN_extrema(a2))
|
||||
expand_extrema!(a1, ignorenan_extrema(a2))
|
||||
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
|
||||
a2[k] = a1[k]
|
||||
end
|
||||
|
||||
+53
-45
@@ -39,7 +39,7 @@ 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)
|
||||
show(io, MIME("image/eps"), plt)
|
||||
close(io)
|
||||
end
|
||||
eps(fn::AbstractString) = eps(current(), fn)
|
||||
@@ -97,6 +97,13 @@ function addExtension(fn::AbstractString, ext::AbstractString)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
savefig([plot,] filename)
|
||||
|
||||
Save a Plot (the current plot if `plot` is not passed) to file. The file
|
||||
type is inferred from the file extension. All backends support png and pdf
|
||||
file types, some also support svg, ps, eps, html and tex.
|
||||
"""
|
||||
function savefig(plt::Plot, fn::AbstractString)
|
||||
|
||||
# get the extension
|
||||
@@ -119,7 +126,11 @@ savefig(fn::AbstractString) = savefig(current(), fn)
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
"""
|
||||
gui([plot])
|
||||
|
||||
Display a plot using the backends' gui window
|
||||
"""
|
||||
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
|
||||
|
||||
# IJulia only... inline display
|
||||
@@ -198,6 +209,7 @@ for mime in keys(_mimeformats)
|
||||
end
|
||||
end
|
||||
|
||||
"Close all open gui windows of the current backend"
|
||||
closeall() = closeall(backend())
|
||||
|
||||
|
||||
@@ -220,14 +232,10 @@ if is_installed("FileIO")
|
||||
FileIO.save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, readall(open(pngfn)))
|
||||
write(io, readstring(open(pngfn)))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# function html_output_format(fmt)
|
||||
# if fmt == "png"
|
||||
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
@@ -250,76 +258,76 @@ end
|
||||
|
||||
const _ijulia_output = String["text/html"]
|
||||
|
||||
function setup_ijulia()
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
@eval begin
|
||||
import IJulia
|
||||
export set_ijulia_output
|
||||
function set_ijulia_output(mimestr::AbstractString)
|
||||
# info("Setting IJulia output format to $mimestr")
|
||||
global _ijulia_output
|
||||
_ijulia_output[1] = mimestr
|
||||
end
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
global _ijulia_output
|
||||
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
|
||||
end
|
||||
using Requires
|
||||
@require IJulia begin
|
||||
if IJulia.inited
|
||||
export set_ijulia_output
|
||||
|
||||
# default text/plain passes to html... handles Interact issues
|
||||
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
|
||||
show(io, MIME("text/html"), plt)
|
||||
end
|
||||
function set_ijulia_output(mimestr::AbstractString)
|
||||
# info("Setting IJulia output format to $mimestr")
|
||||
global _ijulia_output
|
||||
_ijulia_output[1] = mimestr
|
||||
end
|
||||
@eval set_ijulia_output("text/html")
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
global _ijulia_output
|
||||
Dict{String, String}(_ijulia_output[1] => sprint(show, _ijulia_output[1], plt))
|
||||
end
|
||||
|
||||
# default text/plain passes to html... handles Interact issues
|
||||
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
|
||||
show(io, MIME("text/html"), plt)
|
||||
end
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
set_ijulia_output("text/html")
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Atom PlotPane
|
||||
# ---------------------------------------------------------
|
||||
@require Juno begin
|
||||
import Hiccup, Media
|
||||
|
||||
function setup_atom()
|
||||
if isatom()
|
||||
@eval import Atom, Media
|
||||
if Juno.isactive()
|
||||
Media.media(Plot, Media.Plot)
|
||||
|
||||
# default text/plain so it doesn't complain
|
||||
function Base.show{B}(io::IO, ::MIME"text/plain", plt::Plot{B})
|
||||
print(io, "Plot{$B}()")
|
||||
end
|
||||
|
||||
function Media.render(e::Atom.Editor, plt::Plot)
|
||||
Media.render(e, nothing)
|
||||
_show{B}(io::IO, m::MIME"text/plain", plt::Plot{B}) = print(io, "Plot{$B}()")
|
||||
|
||||
function Juno.render(e::Juno.Editor, plt::Plot)
|
||||
Juno.render(e, nothing)
|
||||
end
|
||||
|
||||
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
|
||||
# this is like "display"... sends an html div with the plot to the PlotPane
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot)
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
# temporarily overwrite size to be Atom.plotsize
|
||||
sz = plt[:size]
|
||||
plt[:size] = Juno.plotsize()
|
||||
Media.render(pane, Atom.div(".fill", Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||
jsize = Juno.plotsize()
|
||||
jsize[1] == 0 && (jsize[1] = 400)
|
||||
jsize[2] == 0 && (jsize[2] = 500)
|
||||
|
||||
plt[:size] = jsize
|
||||
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
|
||||
plt[:size] = sz
|
||||
end
|
||||
# special handling for PlotlyJS
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyJSBackend})
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
end
|
||||
else
|
||||
#
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot)
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot)
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
s = "PlotPane turned off. Unset ENV[\"PLOTS_USE_ATOM_PLOTPANE\"] and restart Julia to enable it."
|
||||
Media.render(pane, Atom.div(Atom.HTML(s)))
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
|
||||
# special handling for plotly... use PlotsDisplay
|
||||
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
|
||||
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyBackend})
|
||||
display(Plots.PlotsDisplay(), plt)
|
||||
s = "PlotPane turned off. The plotly backend cannot render in the PlotPane due to javascript issues. Plotlyjs is similar to plotly and is compatible with the plot pane."
|
||||
Media.render(pane, Atom.div(Atom.HTML(s)))
|
||||
Juno.render(pane, HTML(s))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+23
-21
@@ -60,29 +60,26 @@ function _process_userrecipes(plt::Plot, d::KW, args)
|
||||
args = _preprocess_args(d, args, still_to_process)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
# we are keeping a queue of series that still need to be processed.
|
||||
# we are keeping a stack of series that still need to be processed.
|
||||
# each pass through the loop, we pop one off and apply the recipe.
|
||||
# the recipe will return a list a Series objects... the ones that are
|
||||
# finished (no more args) get added to the kw_list, and the rest go into the queue
|
||||
# for processing.
|
||||
# finished (no more args) get added to the kw_list, the ones that are not
|
||||
# are placed on top of the stack and are then processed further.
|
||||
kw_list = KW[]
|
||||
while !isempty(still_to_process)
|
||||
# grab the first in line to be processed and pass it through apply_recipe
|
||||
# to generate a list of RecipeData objects (data + attributes)
|
||||
# grab the first in line to be processed and either add it to the kw_list or
|
||||
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
|
||||
# for further processing.
|
||||
next_series = shift!(still_to_process)
|
||||
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
||||
for recipedata in rd_list
|
||||
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
|
||||
if !(typeof(recipedata) <: RecipeData)
|
||||
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
|
||||
end
|
||||
|
||||
if isempty(recipedata.args)
|
||||
_process_userrecipe(plt, kw_list, recipedata)
|
||||
else
|
||||
# args are non-empty, so there's still processing to do... add it back to the queue
|
||||
push!(still_to_process, recipedata)
|
||||
end
|
||||
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
|
||||
if !(typeof(next_series) <: RecipeData)
|
||||
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
|
||||
end
|
||||
if isempty(next_series.args)
|
||||
_process_userrecipe(plt, kw_list, next_series)
|
||||
else
|
||||
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
|
||||
prepend!(still_to_process,rd_list)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -153,7 +150,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 = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
||||
sy = β * sx + α
|
||||
push!(kw_list, merge(copy(kw), KW(
|
||||
:seriestype => :path,
|
||||
@@ -213,7 +210,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
|
||||
# TODO: init subplots here
|
||||
_update_plot_args(plt, d)
|
||||
if !plt.init
|
||||
plt.o = _create_backend_figure(plt)
|
||||
plt.o = Base.invokelatest(_create_backend_figure, plt)
|
||||
|
||||
# create the layout and subplots from the inputs
|
||||
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
|
||||
@@ -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
|
||||
@@ -367,6 +364,11 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
|
||||
expand_extrema!(sp, d)
|
||||
end
|
||||
# expand for zerolines (axes through origin)
|
||||
if sp[:framestyle] in (:origin, :zerolines)
|
||||
expand_extrema!(sp[:xaxis], 0.0)
|
||||
expand_extrema!(sp[:yaxis], 0.0)
|
||||
end
|
||||
end
|
||||
|
||||
function _add_the_series(plt, sp, d)
|
||||
|
||||
+6
-2
@@ -6,6 +6,10 @@ const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
|
||||
|
||||
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
|
||||
|
||||
"""
|
||||
current()
|
||||
Returns the Plot object for the current plot
|
||||
"""
|
||||
function current()
|
||||
if isplotnull()
|
||||
error("No current plot/subplot")
|
||||
@@ -60,7 +64,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
|
||||
@@ -80,7 +84,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
# TODO: replace this with proper processing from a merged user_attr KW
|
||||
# update plot args, first with existing plots, then override with d
|
||||
for p in plts
|
||||
_update_plot_args(plt, p.attr)
|
||||
_update_plot_args(plt, copy(p.attr))
|
||||
plt.n += p.n
|
||||
end
|
||||
_update_plot_args(plt, d)
|
||||
|
||||
@@ -14,6 +14,12 @@ function lookup_aliases(attrtype, attribute)
|
||||
error("There is no attribute named $attribute in $attrtype")
|
||||
end
|
||||
|
||||
"""
|
||||
plotattr([attr])
|
||||
|
||||
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
|
||||
The information is the same as that given on https://juliaplots.github.io/attributes/.
|
||||
"""
|
||||
function plotattr()
|
||||
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
|
||||
end
|
||||
|
||||
+96
-137
@@ -1,53 +1,4 @@
|
||||
|
||||
|
||||
|
||||
"""
|
||||
You can easily define your own plotting recipes with convenience methods:
|
||||
|
||||
```
|
||||
@userplot type GroupHist
|
||||
args
|
||||
end
|
||||
|
||||
@recipe function f(gh::GroupHist)
|
||||
# set some attributes, add some series, using gh.args as input
|
||||
end
|
||||
|
||||
# now you can plot like:
|
||||
grouphist(rand(1000,4))
|
||||
```
|
||||
"""
|
||||
macro userplot(expr)
|
||||
_userplot(expr)
|
||||
end
|
||||
|
||||
function _userplot(expr::Expr)
|
||||
if expr.head != :type
|
||||
errror("Must call userplot on a type/immutable expression. Got: $expr")
|
||||
end
|
||||
|
||||
typename = expr.args[2]
|
||||
funcname = Symbol(lowercase(string(typename)))
|
||||
funcname2 = Symbol(funcname, "!")
|
||||
|
||||
# return a code block with the type definition and convenience plotting methods
|
||||
esc(quote
|
||||
$expr
|
||||
export $funcname, $funcname2
|
||||
$funcname(args...; kw...) = plot($typename(args); kw...)
|
||||
$funcname2(args...; kw...) = plot!($typename(args); kw...)
|
||||
end)
|
||||
end
|
||||
|
||||
function _userplot(sym::Symbol)
|
||||
_userplot(:(type $sym
|
||||
args
|
||||
end))
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
const _series_recipe_deps = Dict()
|
||||
|
||||
function series_recipe_dependencies(st::Symbol, deps::Symbol...)
|
||||
@@ -96,7 +47,7 @@ end
|
||||
num_series(x::AMat) = size(x,2)
|
||||
num_series(x) = 1
|
||||
|
||||
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::Plot) = throw(MethodError("Unmatched plot recipe: $T"))
|
||||
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::AbstractPlot) = throw(MethodError("Unmatched plot recipe: $T"))
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -128,7 +79,7 @@ function hvline_limits(axis::Axis)
|
||||
end
|
||||
|
||||
@recipe function f(::Type{Val{:hline}}, x, y, z)
|
||||
xmin, xmax = hvline_limits(d[:subplot][:xaxis])
|
||||
xmin, xmax = hvline_limits(plotattributes[:subplot][:xaxis])
|
||||
n = length(y)
|
||||
newx = repmat(Float64[xmin, xmax, NaN], n)
|
||||
newy = vec(Float64[yi for i=1:3,yi=y])
|
||||
@@ -140,7 +91,7 @@ end
|
||||
@deps hline path
|
||||
|
||||
@recipe function f(::Type{Val{:vline}}, x, y, z)
|
||||
ymin, ymax = hvline_limits(d[:subplot][:yaxis])
|
||||
ymin, ymax = hvline_limits(plotattributes[:subplot][:yaxis])
|
||||
n = length(y)
|
||||
newx = vec(Float64[yi for i=1:3,yi=y])
|
||||
newy = repmat(Float64[ymin, ymax, NaN], n)
|
||||
@@ -172,11 +123,11 @@ end
|
||||
|
||||
# create a path from steps
|
||||
@recipe function f(::Type{Val{:steppre}}, x, y, z)
|
||||
d[:x], d[:y] = make_steps(x, y, :steppre)
|
||||
plotattributes[:x], plotattributes[:y] = make_steps(x, y, :steppre)
|
||||
seriestype := :path
|
||||
|
||||
# create a secondary series for the markers
|
||||
if d[:markershape] != :none
|
||||
if plotattributes[:markershape] != :none
|
||||
@series begin
|
||||
seriestype := :scatter
|
||||
x := x
|
||||
@@ -193,11 +144,11 @@ end
|
||||
|
||||
# create a path from steps
|
||||
@recipe function f(::Type{Val{:steppost}}, x, y, z)
|
||||
d[:x], d[:y] = make_steps(x, y, :steppost)
|
||||
plotattributes[:x], plotattributes[:y] = make_steps(x, y, :steppost)
|
||||
seriestype := :path
|
||||
|
||||
# create a secondary series for the markers
|
||||
if d[:markershape] != :none
|
||||
if plotattributes[:markershape] != :none
|
||||
@series begin
|
||||
seriestype := :scatter
|
||||
x := x
|
||||
@@ -219,20 +170,20 @@ end
|
||||
# create vertical line segments from fill
|
||||
@recipe function f(::Type{Val{:sticks}}, x, y, z)
|
||||
n = length(x)
|
||||
fr = d[:fillrange]
|
||||
fr = plotattributes[:fillrange]
|
||||
if fr == nothing
|
||||
yaxis = d[:subplot][:yaxis]
|
||||
yaxis = plotattributes[:subplot][:yaxis]
|
||||
fr = if yaxis[:scale] == :identity
|
||||
0.0
|
||||
else
|
||||
NaNMath.min(axis_limits(yaxis)[1], ignoreNaN_minimum(y))
|
||||
NaNMath.min(axis_limits(yaxis)[1], ignorenan_minimum(y))
|
||||
end
|
||||
end
|
||||
newx, newy = zeros(3n), zeros(3n)
|
||||
for i=1:n
|
||||
rng = 3i-2:3i
|
||||
newx[rng] = [x[i], x[i], NaN]
|
||||
newy[rng] = [cycle(fr,i), y[i], NaN]
|
||||
newy[rng] = [_cycle(fr,i), y[i], NaN]
|
||||
end
|
||||
x := newx
|
||||
y := newy
|
||||
@@ -240,7 +191,7 @@ end
|
||||
seriestype := :path
|
||||
|
||||
# create a secondary series for the markers
|
||||
if d[:markershape] != :none
|
||||
if plotattributes[:markershape] != :none
|
||||
@series begin
|
||||
seriestype := :scatter
|
||||
x := x
|
||||
@@ -273,7 +224,7 @@ end
|
||||
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30)
|
||||
args = z != nothing ? (x,y,z) : (x,y)
|
||||
newx, newy = zeros(0), zeros(0)
|
||||
fr = d[:fillrange]
|
||||
fr = plotattributes[:fillrange]
|
||||
newfr = fr != nothing ? zeros(0) : nothing
|
||||
newz = z != nothing ? zeros(0) : nothing
|
||||
# lz = d[:line_z]
|
||||
@@ -284,16 +235,16 @@ end
|
||||
for rng in iter_segments(args...)
|
||||
length(rng) < 2 && continue
|
||||
ts = linspace(0, 1, npoints)
|
||||
nanappend!(newx, map(t -> bezier_value(cycle(x,rng), t), ts))
|
||||
nanappend!(newy, map(t -> bezier_value(cycle(y,rng), t), ts))
|
||||
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts))
|
||||
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts))
|
||||
if z != nothing
|
||||
nanappend!(newz, map(t -> bezier_value(cycle(z,rng), t), ts))
|
||||
nanappend!(newz, map(t -> bezier_value(_cycle(z,rng), t), ts))
|
||||
end
|
||||
if fr != nothing
|
||||
nanappend!(newfr, map(t -> bezier_value(cycle(fr,rng), t), ts))
|
||||
nanappend!(newfr, map(t -> bezier_value(_cycle(fr,rng), t), ts))
|
||||
end
|
||||
# if lz != nothing
|
||||
# lzrng = cycle(lz, rng) # the line_z's for this segment
|
||||
# lzrng = _cycle(lz, rng) # the line_z's for this segment
|
||||
# push!(newlz, 0.0)
|
||||
# append!(newlz, map(t -> lzrng[1+floor(Int, t * (length(rng)-1))], ts))
|
||||
# end
|
||||
@@ -323,9 +274,9 @@ end
|
||||
|
||||
# create a bar plot as a filled step function
|
||||
@recipe function f(::Type{Val{:bar}}, x, y, z)
|
||||
procx, procy, xscale, yscale, baseline = _preprocess_barlike(d, x, y)
|
||||
procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y)
|
||||
nx, ny = length(procx), length(procy)
|
||||
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
|
||||
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
|
||||
cv = [discrete_value!(axis, xi)[1] for xi=procx]
|
||||
procx = if nx == ny
|
||||
cv
|
||||
@@ -336,15 +287,15 @@ end
|
||||
end
|
||||
|
||||
# compute half-width of bars
|
||||
bw = d[:bar_width]
|
||||
bw = plotattributes[:bar_width]
|
||||
hw = if bw == nothing
|
||||
0.5ignoreNaN_mean(diff(procx))
|
||||
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx)))
|
||||
else
|
||||
Float64[0.5cycle(bw,i) for i=1:length(procx)]
|
||||
Float64[0.5_cycle(bw,i) for i=1:length(procx)]
|
||||
end
|
||||
|
||||
# make fillto a vector... default fills to 0
|
||||
fillto = d[:fillrange]
|
||||
fillto = plotattributes[:fillrange]
|
||||
if fillto == nothing
|
||||
fillto = 0
|
||||
end
|
||||
@@ -358,18 +309,18 @@ end
|
||||
yi = procy[i]
|
||||
if !isnan(yi)
|
||||
center = procx[i]
|
||||
hwi = cycle(hw,i)
|
||||
fi = cycle(fillto,i)
|
||||
hwi = _cycle(hw,i)
|
||||
fi = _cycle(fillto,i)
|
||||
push!(xseg, center-hwi, center-hwi, center+hwi, center+hwi, center-hwi)
|
||||
push!(yseg, yi, fi, fi, yi, yi)
|
||||
end
|
||||
end
|
||||
|
||||
# widen limits out a bit
|
||||
expand_extrema!(axis, widen(ignoreNaN_extrema(xseg.pts)...))
|
||||
expand_extrema!(axis, widen(ignorenan_extrema(xseg.pts)...))
|
||||
|
||||
# switch back
|
||||
if !isvertical(d)
|
||||
if !isvertical(plotattributes)
|
||||
xseg, yseg = yseg, xseg
|
||||
end
|
||||
|
||||
@@ -414,8 +365,8 @@ end
|
||||
|
||||
function _preprocess_binbarlike_weights{T<:AbstractFloat}(::Type{T}, w, wscale::Symbol)
|
||||
w_adj = _scale_adjusted_values(T, w, wscale)
|
||||
w_min = ignoreNaN_minimum(w_adj)
|
||||
w_max = ignoreNaN_maximum(w_adj)
|
||||
w_min = ignorenan_minimum(w_adj)
|
||||
w_max = ignorenan_maximum(w_adj)
|
||||
baseline = _binbarlike_baseline(w_min, wscale)
|
||||
w_adj, baseline
|
||||
end
|
||||
@@ -438,8 +389,8 @@ end
|
||||
|
||||
|
||||
@recipe function f(::Type{Val{:barbins}}, x, y, z)
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
|
||||
if (d[:bar_width] == nothing)
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
|
||||
if (plotattributes[:bar_width] == nothing)
|
||||
bar_width := diff(edge)
|
||||
end
|
||||
x := _bin_centers(edge)
|
||||
@@ -451,7 +402,7 @@ end
|
||||
|
||||
|
||||
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
|
||||
xerror := diff(edge)/2
|
||||
x := _bin_centers(edge)
|
||||
y := weights
|
||||
@@ -514,17 +465,17 @@ end
|
||||
|
||||
|
||||
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
|
||||
axis = d[:subplot][Plots.isvertical(d) ? :xaxis : :yaxis]
|
||||
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
|
||||
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
|
||||
|
||||
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
|
||||
if !isvertical(d)
|
||||
if !isvertical(plotattributes)
|
||||
xpts, ypts = ypts, xpts
|
||||
end
|
||||
|
||||
# create a secondary series for the markers
|
||||
if d[:markershape] != :none
|
||||
if plotattributes[:markershape] != :none
|
||||
@series begin
|
||||
seriestype := :scatter
|
||||
x := _bin_centers(edge)
|
||||
@@ -546,33 +497,40 @@ end
|
||||
end
|
||||
Plots.@deps stepbins path
|
||||
|
||||
wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
||||
|
||||
function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto)
|
||||
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
|
||||
_iqr(v) = quantile(v, 0.75) - quantile(v, 0.25)
|
||||
_span(v) = ignoreNaN_maximum(v) - ignoreNaN_minimum(v)
|
||||
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
|
||||
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
|
||||
|
||||
n_samples = length(linearindices(first(vs)))
|
||||
# Estimator for number of samples in one row/column of bins along each axis:
|
||||
n = max(1, n_samples^(1/N))
|
||||
|
||||
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
|
||||
nd = n_samples^(1/(2+N))
|
||||
nd = N == 2 ? nd / (1-cor(first(vs), last(vs))^2)^(3//8) : nd # the >2-dimensional case does not have a nice solution to correlations
|
||||
|
||||
v = vs[dim]
|
||||
|
||||
if mode == :auto
|
||||
30
|
||||
elseif mode == :sqrt # Square-root choice
|
||||
_cl(sqrt(n))
|
||||
mode = :fd
|
||||
end
|
||||
|
||||
if mode == :sqrt # Square-root choice
|
||||
_cl(sqrt(n_samples))
|
||||
elseif mode == :sturges # Sturges' formula
|
||||
_cl(log2(n)) + 1
|
||||
_cl(log2(n_samples) + 1)
|
||||
elseif mode == :rice # Rice Rule
|
||||
_cl(2 * n^(1/3))
|
||||
_cl(2 * nd)
|
||||
elseif mode == :scott # Scott's normal reference rule
|
||||
_cl(_span(v) / (3.5 * std(v) / n^(1/3)))
|
||||
_cl(_span(v) / (3.5 * std(v) / nd))
|
||||
elseif mode == :fd # Freedman–Diaconis rule
|
||||
_cl(_span(v) / (2 * _iqr(v) / n^(1/3)))
|
||||
_cl(_span(v) / (2 * _iqr(v) / nd))
|
||||
elseif mode == :wand
|
||||
wand_edges(v) # this makes this function not type stable, but the type instability does not propagate
|
||||
else
|
||||
error("Unknown auto-binning mode $mode")
|
||||
end::Int
|
||||
end
|
||||
end
|
||||
|
||||
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) = StatsBase.histrange(vs[dim], binning, :left)
|
||||
@@ -599,13 +557,13 @@ end
|
||||
|
||||
|
||||
@recipe function f(::Type{Val{:histogram}}, x, y, z)
|
||||
seriestype := :barhist
|
||||
seriestype := length(y) > 1e6 ? :stephist : :barhist
|
||||
()
|
||||
end
|
||||
@deps histogram barhist
|
||||
|
||||
@recipe function f(::Type{Val{:barhist}}, x, y, z)
|
||||
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
|
||||
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
||||
x := h.edges[1]
|
||||
y := h.weights
|
||||
seriestype := :barbins
|
||||
@@ -614,7 +572,7 @@ end
|
||||
@deps barhist barbins
|
||||
|
||||
@recipe function f(::Type{Val{:stephist}}, x, y, z)
|
||||
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
|
||||
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
||||
x := h.edges[1]
|
||||
y := h.weights
|
||||
seriestype := :stepbins
|
||||
@@ -623,7 +581,7 @@ end
|
||||
@deps stephist stepbins
|
||||
|
||||
@recipe function f(::Type{Val{:scatterhist}}, x, y, z)
|
||||
h = _make_hist((y,), d[:bins], normed = d[:normalize], weights = d[:weights])
|
||||
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
||||
x := h.edges[1]
|
||||
y := h.weights
|
||||
seriestype := :scatterbins
|
||||
@@ -639,11 +597,11 @@ end
|
||||
:bar => :barbins, :scatter => :scatterbins, :step => :stepbins,
|
||||
:steppost => :stepbins # :step can be mapped to :steppost in pre-processing
|
||||
)
|
||||
seriestype := get(st_map, d[:seriestype], d[:seriestype])
|
||||
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
|
||||
|
||||
if d[:seriestype] == :scatterbins
|
||||
if plotattributes[:seriestype] == :scatterbins
|
||||
# Workaround, error bars currently not set correctly by scatterbins
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, h.edges[1], h.weights)
|
||||
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, h.edges[1], h.weights)
|
||||
xerror --> diff(h.edges[1])/2
|
||||
seriestype := :scatter
|
||||
(Plots._bin_centers(edge), weights)
|
||||
@@ -669,7 +627,7 @@ end
|
||||
edge_x, edge_y, weights = x, y, z.surf
|
||||
|
||||
float_weights = float(weights)
|
||||
if is(float_weights, weights)
|
||||
if float_weights === weights
|
||||
float_weights = deepcopy(float_weights)
|
||||
end
|
||||
for (i, c) in enumerate(float_weights)
|
||||
@@ -690,7 +648,7 @@ Plots.@deps bins2d heatmap
|
||||
|
||||
|
||||
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
|
||||
h = _make_hist((x, y), d[:bins], normed = d[:normalize], weights = d[:weights])
|
||||
h = _make_hist((x, y), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights])
|
||||
x := h.edges[1]
|
||||
y := h.edges[2]
|
||||
z := Surface(h.weights)
|
||||
@@ -711,7 +669,7 @@ end
|
||||
|
||||
@recipe function f(::Type{Val{:scatter3d}}, x, y, z)
|
||||
seriestype := :path3d
|
||||
if d[:markershape] == :none
|
||||
if plotattributes[:markershape] == :none
|
||||
markershape := :circle
|
||||
end
|
||||
linewidth := 0
|
||||
@@ -752,12 +710,12 @@ end
|
||||
|
||||
function error_coords(xorig, yorig, ebar)
|
||||
# init empty x/y, and zip errors if passed Tuple{Vector,Vector}
|
||||
x, y = Array(float_extended_type(xorig), 0), Array(Float64, 0)
|
||||
x, y = Array{float_extended_type(xorig)}(0), Array{Float64}(0)
|
||||
# for each point, create a line segment from the bottom to the top of the errorbar
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
xi = cycle(xorig, i)
|
||||
yi = cycle(yorig, i)
|
||||
ebi = cycle(ebar, i)
|
||||
xi = _cycle(xorig, i)
|
||||
yi = _cycle(yorig, i)
|
||||
ebi = _cycle(ebar, i)
|
||||
nanappend!(x, [xi, xi])
|
||||
e1, e2 = if istuple(ebi)
|
||||
first(ebi), last(ebi)
|
||||
@@ -774,17 +732,17 @@ end
|
||||
# we will create a series of path segments, where each point represents one
|
||||
# side of an errorbar
|
||||
@recipe function f(::Type{Val{:yerror}}, x, y, z)
|
||||
error_style!(d)
|
||||
error_style!(plotattributes)
|
||||
markershape := :hline
|
||||
d[:x], d[:y] = error_coords(d[:x], d[:y], error_zipit(d[:yerror]))
|
||||
plotattributes[:x], plotattributes[:y] = error_coords(plotattributes[:x], plotattributes[:y], error_zipit(plotattributes[:yerror]))
|
||||
()
|
||||
end
|
||||
@deps yerror path
|
||||
|
||||
@recipe function f(::Type{Val{:xerror}}, x, y, z)
|
||||
error_style!(d)
|
||||
error_style!(plotattributes)
|
||||
markershape := :vline
|
||||
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
|
||||
plotattributes[:y], plotattributes[:x] = error_coords(plotattributes[:y], plotattributes[:x], error_zipit(plotattributes[:xerror]))
|
||||
()
|
||||
end
|
||||
@deps xerror path
|
||||
@@ -810,11 +768,11 @@ function quiver_using_arrows(d::KW)
|
||||
x, y = zeros(0), zeros(0)
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
# get the starting position
|
||||
xi = cycle(xorig, i)
|
||||
yi = cycle(yorig, i)
|
||||
xi = _cycle(xorig, i)
|
||||
yi = _cycle(yorig, i)
|
||||
|
||||
# get the velocity
|
||||
vi = cycle(velocity, i)
|
||||
vi = _cycle(velocity, i)
|
||||
vx, vy = if istuple(vi)
|
||||
first(vi), last(vi)
|
||||
elseif isscalar(vi)
|
||||
@@ -847,12 +805,12 @@ function quiver_using_hack(d::KW)
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
|
||||
# get the starting position
|
||||
xi = cycle(xorig, i)
|
||||
yi = cycle(yorig, i)
|
||||
xi = _cycle(xorig, i)
|
||||
yi = _cycle(yorig, i)
|
||||
p = P2(xi, yi)
|
||||
|
||||
# get the velocity
|
||||
vi = cycle(velocity, i)
|
||||
vi = _cycle(velocity, i)
|
||||
vx, vy = if istuple(vi)
|
||||
first(vi), last(vi)
|
||||
elseif isscalar(vi)
|
||||
@@ -883,9 +841,9 @@ end
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
@recipe function f(::Type{Val{:quiver}}, x, y, z)
|
||||
if :arrow in supported_attrs()
|
||||
quiver_using_arrows(d)
|
||||
quiver_using_arrows(plotattributes)
|
||||
else
|
||||
quiver_using_hack(d)
|
||||
quiver_using_hack(plotattributes)
|
||||
end
|
||||
()
|
||||
end
|
||||
@@ -896,6 +854,7 @@ end
|
||||
|
||||
# TODO: move OHLC to PlotRecipes finance.jl
|
||||
|
||||
"Represent Open High Low Close data (used in finance)"
|
||||
type OHLC{T<:Real}
|
||||
open::T
|
||||
high::T
|
||||
@@ -919,7 +878,7 @@ end
|
||||
|
||||
# get the joined vector
|
||||
function get_xy(v::AVec{OHLC}, x = 1:length(v))
|
||||
xdiff = 0.3ignoreNaN_mean(abs(diff(x)))
|
||||
xdiff = 0.3ignorenan_mean(abs.(diff(x)))
|
||||
x_out, y_out = zeros(0), zeros(0)
|
||||
for (i,ohlc) in enumerate(v)
|
||||
ox,oy = get_xy(ohlc, x[i], xdiff)
|
||||
@@ -960,7 +919,7 @@ end
|
||||
|
||||
# "Sparsity plot... heatmap of non-zero values of a matrix"
|
||||
# function spy{T<:Real}(z::AMat{T}; kw...)
|
||||
# mat = map(zi->float(zi!=0), z)'
|
||||
# mat = reshape(map(zi->float(zi!=0), z),1,:)
|
||||
# xn, yn = size(mat)
|
||||
# heatmap(mat; leg=false, yflip=true, aspect_ratio=:equal,
|
||||
# xlim=(0.5, xn+0.5), ylim=(0.5, yn+0.5),
|
||||
@@ -987,12 +946,12 @@ end
|
||||
yflip := true
|
||||
aspect_ratio := 1
|
||||
rs, cs, zs = findnz(z.surf)
|
||||
xlim := ignoreNaN_extrema(cs)
|
||||
ylim := ignoreNaN_extrema(rs)
|
||||
if d[:markershape] == :none
|
||||
xlim := ignorenan_extrema(cs)
|
||||
ylim := ignorenan_extrema(rs)
|
||||
if plotattributes[:markershape] == :none
|
||||
markershape := :circle
|
||||
end
|
||||
if d[:markersize] == default(:markersize)
|
||||
if plotattributes[:markersize] == default(:markersize)
|
||||
markersize := 1
|
||||
end
|
||||
markerstrokewidth := 0
|
||||
@@ -1010,7 +969,7 @@ end
|
||||
|
||||
"Adds a+bx... straight line over the current plot"
|
||||
function abline!(plt::Plot, a, b; kw...)
|
||||
plot!(plt, [ignoreNaN_extrema(plt)...], x -> b + a*x; kw...)
|
||||
plot!(plt, [ignorenan_extrema(plt)...], x -> b + a*x; kw...)
|
||||
end
|
||||
|
||||
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
@@ -1019,11 +978,11 @@ abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
# -------------------------------------------------
|
||||
# Dates
|
||||
|
||||
dateformatter(dt) = string(convert(Date, dt))
|
||||
datetimeformatter(dt) = string(convert(DateTime, dt))
|
||||
dateformatter(dt) = string(Date(Dates.UTD(dt)))
|
||||
datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
|
||||
|
||||
@recipe f(::Type{Date}, dt::Date) = (dt -> convert(Int, dt), dateformatter)
|
||||
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> convert(Int, dt), datetimeformatter)
|
||||
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
|
||||
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
|
||||
|
||||
# -------------------------------------------------
|
||||
# Complex Numbers
|
||||
@@ -1054,7 +1013,7 @@ end
|
||||
end
|
||||
|
||||
library = PlotUtils.color_libraries[cl.args[1]]
|
||||
z = sqrt.((1:15)*(1:20)')
|
||||
z = sqrt.((1:15)*reshape(1:20,1,:))
|
||||
|
||||
seriestype := :heatmap
|
||||
ticks := nothing
|
||||
@@ -1078,7 +1037,7 @@ end
|
||||
if !(length(grad.args) == 1 && isa(grad.args[1], Symbol))
|
||||
error("showgradient takes the name of a color gradient as a Symbol")
|
||||
end
|
||||
z = sqrt.((1:15)*(1:20)')
|
||||
z = sqrt.((1:15)*reshape(1:20,1,:))
|
||||
seriestype := :heatmap
|
||||
ticks := nothing
|
||||
legend := false
|
||||
|
||||
+109
-34
@@ -6,10 +6,13 @@
|
||||
# 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
|
||||
|
||||
typealias FuncOrFuncs{F} Union{F, Vector{F}, Matrix{F}}
|
||||
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
|
||||
|
||||
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
|
||||
|
||||
# unknown
|
||||
convertToAnyVector(x, d::KW) = error("No user recipe defined for $(typeof(x))")
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
|
||||
|
||||
@@ -125,15 +128,15 @@ immutable SliceIt end
|
||||
z = z.data
|
||||
end
|
||||
|
||||
xs, _ = convertToAnyVector(x, d)
|
||||
ys, _ = convertToAnyVector(y, d)
|
||||
zs, _ = convertToAnyVector(z, d)
|
||||
xs, _ = convertToAnyVector(x, plotattributes)
|
||||
ys, _ = convertToAnyVector(y, plotattributes)
|
||||
zs, _ = convertToAnyVector(z, plotattributes)
|
||||
|
||||
fr = pop!(d, :fillrange, nothing)
|
||||
fr = pop!(plotattributes, :fillrange, nothing)
|
||||
fillranges, _ = if typeof(fr) <: Number
|
||||
([fr],nothing)
|
||||
else
|
||||
convertToAnyVector(fr, d)
|
||||
convertToAnyVector(fr, plotattributes)
|
||||
end
|
||||
mf = length(fillranges)
|
||||
|
||||
@@ -145,7 +148,7 @@ immutable SliceIt end
|
||||
if mx > 0 && my > 0 && mz > 0
|
||||
for i in 1:max(mx, my, mz)
|
||||
# add a new series
|
||||
di = copy(d)
|
||||
di = copy(plotattributes)
|
||||
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)
|
||||
|
||||
@@ -171,6 +174,7 @@ _apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
|
||||
# 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)
|
||||
isempty(v) && return Float64[]
|
||||
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
|
||||
@@ -202,11 +206,11 @@ _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
|
||||
newx = _apply_type_recipe(d, x)
|
||||
newx = _apply_type_recipe(plotattributes, x)
|
||||
x === newx || (did_replace = true)
|
||||
newy = _apply_type_recipe(d, y)
|
||||
newy = _apply_type_recipe(plotattributes, y)
|
||||
y === newy || (did_replace = true)
|
||||
newz = _apply_type_recipe(d, z)
|
||||
newz = _apply_type_recipe(plotattributes, z)
|
||||
z === newz || (did_replace = true)
|
||||
if did_replace
|
||||
newx, newy, newz
|
||||
@@ -216,9 +220,9 @@ _apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v
|
||||
end
|
||||
@recipe function f(x, y)
|
||||
did_replace = false
|
||||
newx = _apply_type_recipe(d, x)
|
||||
newx = _apply_type_recipe(plotattributes, x)
|
||||
x === newx || (did_replace = true)
|
||||
newy = _apply_type_recipe(d, y)
|
||||
newy = _apply_type_recipe(plotattributes, y)
|
||||
y === newy || (did_replace = true)
|
||||
if did_replace
|
||||
newx, newy
|
||||
@@ -227,7 +231,7 @@ end
|
||||
end
|
||||
end
|
||||
@recipe function f(y)
|
||||
newy = _apply_type_recipe(d, y)
|
||||
newy = _apply_type_recipe(plotattributes, y)
|
||||
if y !== newy
|
||||
newy
|
||||
else
|
||||
@@ -240,7 +244,7 @@ end
|
||||
@recipe function f(v1, v2, v3, v4, vrest...)
|
||||
did_replace = false
|
||||
newargs = map(v -> begin
|
||||
newv = _apply_type_recipe(d, v)
|
||||
newv = _apply_type_recipe(plotattributes, v)
|
||||
if newv !== v
|
||||
did_replace = true
|
||||
end
|
||||
@@ -267,13 +271,13 @@ function wrap_surfaces(d::KW)
|
||||
end
|
||||
end
|
||||
|
||||
@recipe f(n::Integer) = is3d(get(d,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
|
||||
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
|
||||
|
||||
# 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})
|
||||
if all3D(d)
|
||||
if all3D(plotattributes)
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(d)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
SliceIt, nothing, mat, nothing
|
||||
@@ -282,10 +286,10 @@ 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)
|
||||
if all3D(plotattributes)
|
||||
mat = fmt.data
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(d)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
|
||||
else
|
||||
SliceIt, nothing, fmt, nothing
|
||||
@@ -318,14 +322,14 @@ end
|
||||
|
||||
@recipe function f{T<:Colorant}(mat::AMat{T})
|
||||
n, m = size(mat)
|
||||
|
||||
|
||||
if is_seriestype_supported(:image)
|
||||
seriestype := :image
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
else
|
||||
seriestype := :heatmap
|
||||
yflip --> true
|
||||
z, d[:fillcolor] = replace_image_with_heatmap(mat)
|
||||
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
|
||||
SliceIt, 1:m, 1:n, Surface(z)
|
||||
end
|
||||
end
|
||||
@@ -355,15 +359,35 @@ end
|
||||
# function without range... use the current range of the x-axis
|
||||
|
||||
@recipe function f{F<:Function}(f::FuncOrFuncs{F})
|
||||
plt = d[:plot_object]
|
||||
plt = plotattributes[:plot_object]
|
||||
xmin, xmax = try
|
||||
axis_limits(plt[1][:xaxis])
|
||||
catch
|
||||
-5, 5
|
||||
xm = tryrange(f, [-5,-1,0,0.01])
|
||||
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
|
||||
end
|
||||
|
||||
f, xmin, xmax
|
||||
end
|
||||
|
||||
# try some intervals over which the function may be defined
|
||||
function tryrange(F::AbstractArray, vec)
|
||||
rets = [tryrange(f, vec) for f in F] # get the preferred for each
|
||||
maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all)
|
||||
rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there
|
||||
rets[1]
|
||||
end
|
||||
|
||||
function tryrange(F, vec)
|
||||
for v in vec
|
||||
try
|
||||
tmp = F(v)
|
||||
return v
|
||||
catch
|
||||
end
|
||||
end
|
||||
error("$F is not a Function, or is not defined at any of the values $vec")
|
||||
end
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # 2 arguments
|
||||
@@ -404,7 +428,7 @@ end
|
||||
# seriestype := :path3d
|
||||
# end
|
||||
# end
|
||||
wrap_surfaces(d)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, x, y, z
|
||||
end
|
||||
|
||||
@@ -414,7 +438,7 @@ 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)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
||||
end
|
||||
|
||||
@@ -422,10 +446,10 @@ end
|
||||
# # surface-like... matrix grid
|
||||
|
||||
@recipe function f(x::AVec, y::AVec, z::AMat)
|
||||
if !like_surface(get(d, :seriestype, :none))
|
||||
d[:seriestype] = :contour
|
||||
if !like_surface(get(plotattributes, :seriestype, :none))
|
||||
plotattributes[:seriestype] = :contour
|
||||
end
|
||||
wrap_surfaces(d)
|
||||
wrap_surfaces(plotattributes)
|
||||
SliceIt, x, y, Surface(z)
|
||||
end
|
||||
|
||||
@@ -477,7 +501,7 @@ end
|
||||
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
|
||||
# these might be points+velocity, or OHLC or something else
|
||||
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(d,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
|
||||
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
|
||||
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
|
||||
|
||||
|
||||
@@ -509,13 +533,64 @@ end
|
||||
# nothing
|
||||
# end
|
||||
|
||||
splittable_kw(key, val, lengthGroup) = false
|
||||
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
|
||||
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
|
||||
|
||||
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val)-1)...]
|
||||
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
|
||||
|
||||
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
|
||||
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
|
||||
fill!(y_mat, def_val)
|
||||
for i in 1:length(groupby.groupLabels)
|
||||
xi = x[groupby.groupIds[i]]
|
||||
yi = y[groupby.groupIds[i]]
|
||||
y_mat[getindex.(x_ind, xi), i] = yi
|
||||
end
|
||||
return y_mat
|
||||
end
|
||||
|
||||
groupedvec2mat(x_ind, x, y::Tuple, groupby) = Tuple(groupedvec2mat(x_ind, x, v, groupby) for v in y)
|
||||
|
||||
group_as_matrix(t) = false
|
||||
|
||||
# split the group into 1 series per group, and set the label and idxfilter for each
|
||||
@recipe function f(groupby::GroupBy, args...)
|
||||
for (i,glab) in enumerate(groupby.groupLabels)
|
||||
@series begin
|
||||
label --> string(glab)
|
||||
idxfilter --> groupby.groupIds[i]
|
||||
args
|
||||
lengthGroup = maximum(union(groupby.groupIds...))
|
||||
if !(group_as_matrix(args[1]))
|
||||
for (i,glab) in enumerate(groupby.groupLabels)
|
||||
@series begin
|
||||
label --> string(glab)
|
||||
idxfilter --> groupby.groupIds[i]
|
||||
for (key,val) in plotattributes
|
||||
if splittable_kw(key, val, lengthGroup)
|
||||
:($key) := split_kw(key, val, groupby.groupIds[i])
|
||||
end
|
||||
end
|
||||
args
|
||||
end
|
||||
end
|
||||
else
|
||||
g = args[1]
|
||||
if length(g.args) == 1
|
||||
x = zeros(Int64, lengthGroup)
|
||||
for indexes in groupby.groupIds
|
||||
x[indexes] = 1:length(indexes)
|
||||
end
|
||||
last_args = g.args
|
||||
else
|
||||
x = g.args[1]
|
||||
last_args = g.args[2:end]
|
||||
end
|
||||
x_u = unique(x)
|
||||
x_ind = Dict(zip(x_u, 1:length(x_u)))
|
||||
for (key,val) in plotattributes
|
||||
if splittable_kw(key, val, lengthGroup)
|
||||
:($key) := groupedvec2mat(x_ind, x, val, groupby)
|
||||
end
|
||||
end
|
||||
label --> reshape(groupby.groupLabels, 1, :)
|
||||
typeof(g)((x_u, (groupedvec2mat(x_ind, x, arg, groupby, NaN) for arg in last_args)...))
|
||||
end
|
||||
end
|
||||
|
||||
+6
-1
@@ -13,6 +13,11 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
|
||||
)
|
||||
end
|
||||
|
||||
"""
|
||||
plotarea(subplot)
|
||||
|
||||
Return the bounding box of a subplot
|
||||
"""
|
||||
plotarea(sp::Subplot) = sp.plotarea
|
||||
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
|
||||
|
||||
@@ -32,7 +37,7 @@ 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(_ -> _ === sp, plt.subplots)
|
||||
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(x -> x === sp, plt.subplots)
|
||||
|
||||
series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
"""
|
||||
theme(s::Symbol)
|
||||
|
||||
Specify the colour theme for plots.
|
||||
"""
|
||||
function theme(s::Symbol; kw...)
|
||||
# reset?
|
||||
if s == :none || s == :default
|
||||
|
||||
@@ -8,10 +8,6 @@ const KW = Dict{Symbol,Any}
|
||||
|
||||
immutable PlotsDisplay <: Display end
|
||||
|
||||
abstract AbstractBackend
|
||||
abstract AbstractPlot{T<:AbstractBackend}
|
||||
abstract AbstractLayout
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
immutable InputWrapper{T}
|
||||
|
||||
+152
-33
@@ -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 = ignorenan_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 = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
||||
regy = β * regx + α
|
||||
regx, regy
|
||||
end
|
||||
@@ -137,7 +137,7 @@ function imageHack(d::KW)
|
||||
end
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
|
||||
"Build line segments for plotting"
|
||||
type Segments{T}
|
||||
pts::Vector{T}
|
||||
end
|
||||
@@ -185,6 +185,7 @@ type SegmentsIterator
|
||||
args::Tuple
|
||||
n::Int
|
||||
end
|
||||
|
||||
function iter_segments(args...)
|
||||
tup = Plots.wraptuple(args)
|
||||
n = maximum(map(length, tup))
|
||||
@@ -192,7 +193,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)
|
||||
|
||||
@@ -243,19 +244,19 @@ notimpl() = error("This has not been implemented yet")
|
||||
isnothing(x::Void) = true
|
||||
isnothing(x) = false
|
||||
|
||||
cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
|
||||
cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
|
||||
_cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
|
||||
_cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
|
||||
|
||||
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
|
||||
_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
|
||||
|
||||
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(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)
|
||||
_cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
|
||||
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
|
||||
|
||||
makevec(v::AVec) = v
|
||||
makevec{T}(v::T) = T[v]
|
||||
@@ -283,7 +284,7 @@ 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)
|
||||
e1, e2 = ignorenan_extrema(x)
|
||||
lims[1] = NaNMath.min(lims[1], e1)
|
||||
lims[2] = NaNMath.max(lims[2], e2)
|
||||
# catch err
|
||||
@@ -292,7 +293,7 @@ function _expand_limits(lims, x)
|
||||
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 +325,7 @@ function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
|
||||
end
|
||||
end
|
||||
|
||||
createSegments(z) = collect(repmat(z',2,1))[2:end]
|
||||
createSegments(z) = collect(repmat(reshape(z,1,:),2,1))[2:end]
|
||||
|
||||
Base.first(c::Colorant) = c
|
||||
Base.first(x::Symbol) = x
|
||||
@@ -332,19 +333,32 @@ 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)
|
||||
vmin, vmax = ignoreNaN_extrema(v)
|
||||
extra = 0.5 * (vmax-vmin) / (length(v)-1)
|
||||
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
|
||||
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)
|
||||
end
|
||||
|
||||
|
||||
function calc_r_extrema(x, y)
|
||||
xmin, xmax = ignoreNaN_extrema(x)
|
||||
ymin, ymax = ignoreNaN_extrema(y)
|
||||
xmin, xmax = ignorenan_extrema(x)
|
||||
ymin, ymax = ignorenan_extrema(y)
|
||||
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
|
||||
ignoreNaN_extrema(r)
|
||||
ignorenan_extrema(r)
|
||||
end
|
||||
|
||||
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
||||
@@ -355,8 +369,8 @@ function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
||||
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
|
||||
@@ -469,7 +483,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.cycle(rib)))
|
||||
for (i, (yi, ri)) in enumerate(zip(y, Base.Iterators.cycle(rib)))
|
||||
frs[i] = yi + ri
|
||||
end
|
||||
frs
|
||||
@@ -480,16 +494,44 @@ function make_fillrange_from_ribbon(kw::KW)
|
||||
y, rib = kw[:y], kw[:ribbon]
|
||||
rib = wraptuple(rib)
|
||||
rib1, rib2 = -first(rib), last(rib)
|
||||
kw[:ribbon] = nothing
|
||||
# kw[:ribbon] = nothing
|
||||
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
|
||||
(get(kw, :fillalpha, nothing) == nothing) && (kw[:fillalpha] = 0.5)
|
||||
end
|
||||
|
||||
#turn tuple of fillranges to one path
|
||||
function concatenate_fillrange(x,y::Tuple)
|
||||
rib1, rib2 = first(y), last(y)
|
||||
yline = vcat(rib1,(rib2)[end:-1:1])
|
||||
xline = vcat(x,x[end:-1:1])
|
||||
return xline, yline
|
||||
end
|
||||
|
||||
function get_sp_lims(sp::Subplot, letter::Symbol)
|
||||
axis_limits(sp[Symbol(letter, :axis)])
|
||||
end
|
||||
|
||||
"""
|
||||
xlims([plt])
|
||||
|
||||
Returns the x axis limits of the current plot or subplot
|
||||
"""
|
||||
xlims(sp::Subplot) = get_sp_lims(sp, :x)
|
||||
|
||||
"""
|
||||
ylims([plt])
|
||||
|
||||
Returns the y axis limits of the current plot or subplot
|
||||
"""
|
||||
ylims(sp::Subplot) = get_sp_lims(sp, :y)
|
||||
|
||||
"""
|
||||
zlims([plt])
|
||||
|
||||
Returns the z axis limits of the current plot or subplot
|
||||
"""
|
||||
zlims(sp::Subplot) = get_sp_lims(sp, :z)
|
||||
|
||||
xlims(plt::Plot, sp_idx::Int = 1) = xlims(plt[sp_idx])
|
||||
ylims(plt::Plot, sp_idx::Int = 1) = ylims(plt[sp_idx])
|
||||
zlims(plt::Plot, sp_idx::Int = 1) = zlims(plt[sp_idx])
|
||||
@@ -497,6 +539,83 @@ 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)
|
||||
|
||||
|
||||
function get_clims(sp::Subplot)
|
||||
zmin, zmax = Inf, -Inf
|
||||
for series in series_list(sp)
|
||||
for vals in (series[:z], series[:line_z], series[:marker_z], series[:fill_z])
|
||||
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Real)
|
||||
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals.surf)...)
|
||||
elseif (vals != nothing) && (eltype(vals) <: Real)
|
||||
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...)
|
||||
end
|
||||
end
|
||||
end
|
||||
clims = sp[:clims]
|
||||
if is_2tuple(clims)
|
||||
isfinite(clims[1]) && (zmin = clims[1])
|
||||
isfinite(clims[2]) && (zmax = clims[2])
|
||||
end
|
||||
return zmin < zmax ? (zmin, zmax) : (0.0, 0.0)
|
||||
end
|
||||
|
||||
_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax)
|
||||
|
||||
function hascolorbar(series::Series)
|
||||
st = series[:seriestype]
|
||||
hascbar = st in (:heatmap, :contour)
|
||||
if series[:marker_z] != nothing || series[:line_z] != nothing || series[:fill_z] != nothing
|
||||
hascbar = true
|
||||
end
|
||||
# no colorbar if we are creating a surface LightSource
|
||||
if xor(st == :surface, series[:fill_z] != nothing)
|
||||
hascbar = true
|
||||
end
|
||||
return hascbar
|
||||
end
|
||||
|
||||
function hascolorbar(sp::Subplot)
|
||||
cbar = sp[:colorbar]
|
||||
hascbar = false
|
||||
if cbar != :none
|
||||
for series in series_list(sp)
|
||||
if hascolorbar(series)
|
||||
hascbar = true
|
||||
end
|
||||
end
|
||||
end
|
||||
hascbar
|
||||
end
|
||||
|
||||
function get_linecolor(sp::Subplot, series::Series, i::Int = 1)
|
||||
lc = series[:linecolor]
|
||||
lz = series[:line_z]
|
||||
if lz == nothing
|
||||
isa(lc, ColorGradient) ? lc : _cycle(lc, i)
|
||||
else
|
||||
cmin, cmax = get_clims(sp)
|
||||
grad = isa(lc, ColorGradient) ? lc : cgrad()
|
||||
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
end
|
||||
end
|
||||
|
||||
function get_fillcolor(sp::Subplot, series::Series, i::Int = 1)
|
||||
fc = series[:fillcolor]
|
||||
fz = series[:fill_z]
|
||||
lz = series[:line_z]
|
||||
if fz == nothing && lz == nothing
|
||||
isa(fc, ColorGradient) ? fc : _cycle(fc, i)
|
||||
else
|
||||
cmin, cmax = get_clims(sp)
|
||||
grad = isa(fc, ColorGradient) ? fc : cgrad()
|
||||
if fz != nothing
|
||||
grad[clamp((_cycle(fz, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
elseif lz != nothing
|
||||
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
makekw(; kw...) = KW(kw)
|
||||
@@ -523,7 +642,7 @@ allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
|
||||
"""
|
||||
Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example:
|
||||
```
|
||||
with(:gadfly, size=(400,400), type=:histogram) do
|
||||
with(:gr, size=(400,400), type=:histogram) do
|
||||
plot(rand(10))
|
||||
plot(rand(10))
|
||||
end
|
||||
@@ -645,7 +764,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) + ignorenan_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)
|
||||
@@ -871,9 +990,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) = ignorenan_minimum([ignorenan_minimum(series.d[:x]) for series in plt.series_list])
|
||||
"Largest x in plot"
|
||||
xmax(plt::Plot) = ignoreNaN_maximum([ignoreNaN_maximum(series.d[:x]) for series in plt.series_list])
|
||||
xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series in plt.series_list])
|
||||
|
||||
"Extrema of x-values in plot"
|
||||
ignoreNaN_extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
StatPlots
|
||||
FactCheck
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
@@ -7,4 +6,3 @@ GR
|
||||
RDatasets
|
||||
VisualRegressionTests
|
||||
UnicodePlots
|
||||
Glob
|
||||
|
||||
+6
-10
@@ -13,10 +13,9 @@ try
|
||||
end
|
||||
|
||||
|
||||
# using Plots # reexported by StatPlots
|
||||
using Plots
|
||||
using StatPlots
|
||||
using FactCheck
|
||||
using Glob
|
||||
using Base.Test
|
||||
|
||||
default(size=(500,300))
|
||||
|
||||
@@ -24,7 +23,7 @@ default(size=(500,300))
|
||||
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
|
||||
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
|
||||
|
||||
const _current_plots_version = v"0.11.3"
|
||||
const _current_plots_version = v"0.12.4"
|
||||
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
@@ -43,11 +42,8 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
|
||||
fn = "ref$idx.png"
|
||||
|
||||
# firgure out version info
|
||||
G = glob(joinpath(relpath(refdir), "*"))
|
||||
# @show refdir fn G
|
||||
slash = (@static is_windows() ? "\\" : "/")
|
||||
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
|
||||
versions = reverse(sort(versions))
|
||||
vns = filter(x->x[1] != '.', readdir(refdir))
|
||||
versions = sort(VersionNumber.(vns), rev = true)
|
||||
versions = filter(v -> v <= _current_plots_version, versions)
|
||||
# @show refdir fn versions
|
||||
|
||||
@@ -99,7 +95,7 @@ function image_comparison_facts(pkg::Symbol;
|
||||
for i in 1:length(Plots._examples)
|
||||
i in skip && continue
|
||||
if only == nothing || i in only
|
||||
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
|
||||
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,8 +6,8 @@ sudo apt-get -qq update
|
||||
# sudo apt-get install -y wkhtmltopdf
|
||||
|
||||
sudo apt-get install -y xfonts-75dpi xfonts-base
|
||||
wget https://downloads.wkhtmltopdf.org/0.12/0.12.2/wkhtmltox-0.12.2_linux-precise-amd64.deb
|
||||
sudo dpkg -i wkhtmltox-0.12.2_linux-precise-amd64.deb
|
||||
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
|
||||
sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb
|
||||
# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
# sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
|
||||
wkhtmltoimage http://www.google.com test.png
|
||||
|
||||
+52
-51
@@ -7,41 +7,36 @@ srand(1234)
|
||||
default(show=false, reuse=true)
|
||||
img_eps = isinteractive() ? 1e-2 : 10e-2
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
facts("GR") do
|
||||
@fact gr() --> Plots.GRBackend()
|
||||
@fact backend() --> Plots.GRBackend()
|
||||
@testset "GR" begin
|
||||
ENV["GKSwstype"] = "100"
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
image_comparison_facts(:gr, eps=img_eps)
|
||||
end
|
||||
|
||||
|
||||
facts("PyPlot") do
|
||||
@fact pyplot() --> Plots.PyPlotBackend()
|
||||
@fact backend() --> Plots.PyPlotBackend()
|
||||
@testset "PyPlot" begin
|
||||
@test pyplot() == Plots.PyPlotBackend()
|
||||
@test backend() == Plots.PyPlotBackend()
|
||||
|
||||
image_comparison_facts(:pyplot, eps=img_eps)
|
||||
end
|
||||
|
||||
@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)
|
||||
|
||||
# facts("PlotlyJS") do
|
||||
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
|
||||
# @fact backend() --> Plots.PlotlyJSBackend()
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# if is_linux() && isinteractive()
|
||||
# image_comparison_facts(:plotlyjs,
|
||||
@@ -59,9 +54,9 @@ end
|
||||
# ERROR: LoadError: InitError: Cannot open display:
|
||||
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
|
||||
|
||||
# facts("InspectDR") do
|
||||
# @fact inspectdr() --> Plots.InspectDRBackend()
|
||||
# @fact backend() --> Plots.InspectDRBackend()
|
||||
# @testset "InspectDR" begin
|
||||
# @test inspectdr() == Plots.InspectDRBackend()
|
||||
# @test backend() == Plots.InspectDRBackend()
|
||||
#
|
||||
# image_comparison_facts(:inspectdr,
|
||||
# skip=[
|
||||
@@ -78,61 +73,69 @@ end
|
||||
# end
|
||||
|
||||
|
||||
# facts("Plotly") do
|
||||
# @fact plotly() --> Plots.PlotlyBackend()
|
||||
# @fact backend() --> Plots.PlotlyBackend()
|
||||
# @testset "Plotly" begin
|
||||
# @test plotly() == Plots.PlotlyBackend()
|
||||
# @test backend() == Plots.PlotlyBackend()
|
||||
#
|
||||
# # # until png generation is reliable on OSX, just test on linux
|
||||
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# facts("Immerse") do
|
||||
# @fact immerse() --> Plots.ImmerseBackend()
|
||||
# @fact backend() --> Plots.ImmerseBackend()
|
||||
# @testset "Immerse" begin
|
||||
# @test immerse() == Plots.ImmerseBackend()
|
||||
# @test backend() == Plots.ImmerseBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Gadfly
|
||||
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
# facts("PlotlyJS") do
|
||||
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
|
||||
# @fact backend() --> Plots.PlotlyJSBackend()
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Plotly
|
||||
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
|
||||
# end
|
||||
|
||||
|
||||
facts("UnicodePlots") do
|
||||
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
|
||||
@fact backend() --> Plots.UnicodePlotsBackend()
|
||||
|
||||
# lets just make sure it runs without error
|
||||
@fact isa(plot(rand(10)), Plots.Plot) --> true
|
||||
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("Axes") do
|
||||
|
||||
@testset "Axes" begin
|
||||
p = plot()
|
||||
axis = p.subplots[1][:xaxis]
|
||||
@fact typeof(axis) --> Plots.Axis
|
||||
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
|
||||
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
|
||||
@fact Plots.ignoreNaN_extrema(axis) --> (0.5,1.5)
|
||||
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
@test typeof(axis) == Plots.Axis
|
||||
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
|
||||
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5,1.5)
|
||||
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
|
||||
|
||||
Plots.discrete_value!(axis, ["x$i" for i=1:5])
|
||||
Plots.discrete_value!(axis, ["x$i" for i=0:2])
|
||||
@fact Plots.ignoreNaN_extrema(axis) --> (0.5, 7.5)
|
||||
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
|
||||
end
|
||||
|
||||
@testset "NoFail" begin
|
||||
histogram([1, 0, 0, 0, 0, 0])
|
||||
end
|
||||
|
||||
# tests for preprocessing recipes
|
||||
|
||||
# facts("recipes") do
|
||||
# @testset "recipes" begin
|
||||
|
||||
# user recipe
|
||||
|
||||
@@ -169,6 +172,4 @@ end
|
||||
# end
|
||||
|
||||
|
||||
|
||||
FactCheck.exitstatus()
|
||||
end # module
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Pkg.clone("ImageMagick")
|
||||
Pkg.add("ImageMagick")
|
||||
Pkg.build("ImageMagick")
|
||||
|
||||
Pkg.clone("GR")
|
||||
|
||||
Reference in New Issue
Block a user