Compare commits
207 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f11b976574 | |||
| 59da5d5deb | |||
| 0deb7038e6 | |||
| 2ef692c690 | |||
| 9228c0b9ec | |||
| 89d02b1d67 | |||
| a63a9248d6 | |||
| 79777adc07 | |||
| 5619feb6c0 | |||
| f15a721db6 | |||
| d6b3b68cd9 | |||
| 78785fa8fe | |||
| 74c69f575f | |||
| 12e34bb24f | |||
| 4ac5484b4f | |||
| 8306619faf | |||
| 5673477428 | |||
| 84c5b67574 | |||
| e71a15d46e | |||
| daf9556bed | |||
| b6a7c1036c | |||
| 8c2a66b00c | |||
| a1182e0ebe | |||
| 750492f9e3 | |||
| c6893f6cb5 | |||
| 64e035c53c | |||
| adbe515af7 | |||
| f0dac1630f | |||
| ddaa69bce2 | |||
| bb7c2fd660 | |||
| 8dfca61769 | |||
| bb3c54cb27 | |||
| 2816b1128f | |||
| cf0cf972e3 | |||
| bb0e783c02 | |||
| a7b7c5ba81 | |||
| 7214b8b1b1 | |||
| db1e25252a | |||
| 7a248331e7 | |||
| 161ffdee94 | |||
| b3e8fd9c66 | |||
| 538135bc5f | |||
| 0aac0398e8 | |||
| 552024ff31 | |||
| 2f14c37c59 | |||
| 7f8dc486bb | |||
| a89b42229a | |||
| e061d156bc | |||
| 8f4753a0bb | |||
| 068523fac1 | |||
| b3336229ab | |||
| 80c1cb954d | |||
| 0f6336b3dd | |||
| cd1ee47ace | |||
| 46ed2f6263 | |||
| 63f6128c87 | |||
| 9f9ac4ec92 | |||
| 7cf223a5b8 | |||
| 589643d591 | |||
| 3509648553 | |||
| 94841669bf | |||
| fadc0bf6c7 | |||
| fd2c01808a | |||
| 8342da1ea2 | |||
| e9abb6d021 | |||
| 505989eec7 | |||
| 08a30b255d | |||
| 1543c77a39 | |||
| 4c22a421a1 | |||
| 972c97d5ec | |||
| fd611b3647 | |||
| 71cbaa843c | |||
| bbf8b50ad6 | |||
| ddd083b8c1 | |||
| 03f6c76b53 | |||
| 6d6d4f14b5 | |||
| 0735a3475c | |||
| 9a445d529d | |||
| 1ea5a5ac0b | |||
| bc8370eadd | |||
| cdc5a2b361 | |||
| 4270ac80fb | |||
| 405df5da8b | |||
| f742ae4c88 | |||
| a99783dfa0 | |||
| 9af5edd04d | |||
| d0830b90be | |||
| 8cd48bc660 | |||
| 379a320d2d | |||
| d5f3a3ef69 | |||
| a3be970f29 | |||
| 63f8f52c9f | |||
| 169851564c | |||
| c32b9029d1 | |||
| 3fe60b9d18 | |||
| 34cff752f1 | |||
| 0dba83daf6 | |||
| c399092261 | |||
| dcabb2c579 | |||
| 3542785021 | |||
| 65173e6dd2 | |||
| bf0bb68e28 | |||
| 21774dc36b | |||
| 0e3a9f0b8f | |||
| 903cb404c3 | |||
| 03325533bf | |||
| 710123aab4 | |||
| 4742ec972b | |||
| e860ba220a | |||
| 39605bccc2 | |||
| 1a4f411b8f | |||
| a6588daa3e | |||
| b053366b06 | |||
| e838ac502d | |||
| 6131154dd0 | |||
| 0c67a61e7d | |||
| 72696a4326 | |||
| 3231f4d9b1 | |||
| 8a81b398cf | |||
| a37a1a0004 | |||
| b6b00c843a | |||
| 5506c0543c | |||
| 7a1b48311c | |||
| 0b3dafcd18 | |||
| 81f6b3c7bd | |||
| c2da4acb48 | |||
| 841b05631d | |||
| a6e60aea04 | |||
| 7f2a1db64a | |||
| 926ccdf618 | |||
| 9774eca8e2 | |||
| 2ad033f8e2 | |||
| 7c26ffee51 | |||
| aa37ba0463 | |||
| d61c86b54b | |||
| e72fa1dc74 | |||
| 16db531cce | |||
| 226023043b | |||
| 5d2538c4c2 | |||
| 0075103ddf | |||
| 8982a67902 | |||
| 65ab45ff1b | |||
| 577d434bc8 | |||
| b300e634f6 | |||
| 61d13b9b2d | |||
| 78059bf825 | |||
| dd02a69e8f | |||
| 5ec80ad1f1 | |||
| 4849772435 | |||
| 6546879d3a | |||
| cbc379daa9 | |||
| a7be08ef46 | |||
| 47e48e5d27 | |||
| 968b8109dd | |||
| 19fba27951 | |||
| b78da20d04 | |||
| 5e445b4a71 | |||
| 0e5df883d0 | |||
| b79ea119ea | |||
| b21d98affd | |||
| d83666bed3 | |||
| cab6ca3ef0 | |||
| 33a37f9494 | |||
| 79e978aac9 | |||
| 3af60a81f8 | |||
| 56525ced92 | |||
| 581f3797bc | |||
| 2c8d51988b | |||
| 19243b741a | |||
| afc1e08f21 | |||
| 80c01e74c6 | |||
| d728bfb90c | |||
| 203d73ee26 | |||
| 05fe220102 | |||
| c4f2de198e | |||
| 50f9846836 | |||
| a33b3cfbd8 | |||
| 248f7cce90 | |||
| 8f381e2611 | |||
| f4b14d0d8d | |||
| 93428815e4 | |||
| 6b70610770 | |||
| 84eead47e3 | |||
| 009d03f1f8 | |||
| 9482a247e7 | |||
| 022c79fa95 | |||
| a9ed4ac21d | |||
| 354e39e9bf | |||
| 757e08c6fe | |||
| 33e5775294 | |||
| 5b73a8ed1c | |||
| f864ebbf1a | |||
| 54b6051315 | |||
| ebea34920b | |||
| 44294306ce | |||
| c2af1a0666 | |||
| 8f30696a4d | |||
| b58082a37b | |||
| a594878860 | |||
| 3a2b6296ac | |||
| 87af609a6f | |||
| a0d5d0f3c8 | |||
| 53510f3268 | |||
| 9d5ce9753a | |||
| d7a2df41fa | |||
| 5a54fb7e9f | |||
| fef45dfc30 |
@@ -7,3 +7,4 @@ examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-latest.min.js
|
||||
deps/build.log
|
||||
deps/deps.jl
|
||||
Manifest.toml
|
||||
|
||||
+5
-45
@@ -4,57 +4,17 @@ os:
|
||||
- linux
|
||||
# - osx
|
||||
julia:
|
||||
# - 1.0
|
||||
- 1.1
|
||||
- nightly
|
||||
# matrix:
|
||||
# allow_failures:
|
||||
# - julia: nightly
|
||||
|
||||
# # before install:
|
||||
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install wkhtmltopdf; fi
|
||||
|
||||
# ref: http://askubuntu.com/a/556672 for the wkhtmltopdf apt repository info
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- julia: nightly
|
||||
|
||||
sudo: required
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test/install_wkhtmltoimage.sh ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:pov/wkhtmltopdf ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y wkhtmltopdf ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltopdf -V ; fi
|
||||
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltoimage -V ; fi
|
||||
# echo 'exec xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@"' | sudo tee /usr/local/bin/wkhtmltopdf.sh >/dev/null
|
||||
# sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh
|
||||
|
||||
# # borrowed from Blink.jl's travis file
|
||||
# matrix:
|
||||
# include:
|
||||
# - os: linux
|
||||
# julia: 0.4
|
||||
# env: TESTCMD="xvfb-run julia"
|
||||
# - os: osx
|
||||
# julia: 0.4
|
||||
# env: TESTCMD="julia"
|
||||
|
||||
|
||||
|
||||
notifications:
|
||||
email: true
|
||||
# uncomment the following lines to override the default test script
|
||||
# script:
|
||||
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
# - julia -e 'import Pkg; Pkg.add(Pkg.PackageSpec(path=pwd())); Pkg.build("Plots")'
|
||||
# - julia test/travis_commands.jl
|
||||
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
|
||||
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
|
||||
# - julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/JunoLab/Blink.jl.git"); Pkg.build("Blink"); import Blink; Blink.AtomShell.install()'
|
||||
# # - julia -e 'Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")'
|
||||
# - julia -e 'ENV["PYTHON"] = ""; Pkg.add("PyPlot"); Pkg.build("PyPlot")'
|
||||
#
|
||||
# # - $TESTCMD -e 'Pkg.test("Plots"; coverage=false)'
|
||||
# - julia -e 'Pkg.test("Plots"; coverage=false)'
|
||||
# # - julia -e 'cd(Pkg.dir("Plots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
|
||||
|
||||
@@ -11,6 +11,90 @@
|
||||
---
|
||||
## (current master)
|
||||
|
||||
## 0.26.1
|
||||
- handle `Char`s as input data
|
||||
- fix html saving for Plotly
|
||||
- expand ~ in paths on UNIX systems
|
||||
- convertToAnyVector clean-up
|
||||
- fix color_palette grouping issue
|
||||
|
||||
## 0.26.0
|
||||
- use FFMPEG.jl
|
||||
- add missing method for convertToAnyVector
|
||||
|
||||
## 0.25.3
|
||||
- add areaplot
|
||||
- allow missing in z_color arguments
|
||||
- more general tuple recipe
|
||||
- stephist logscale improvements
|
||||
|
||||
## 0.25.2
|
||||
- improvements to handle missings
|
||||
- pyplot: allow setting the color gradient for z values
|
||||
- document :colorbar_entry
|
||||
- limit number of automatic bins
|
||||
- fix ENV['PLOTS_DEFAULT_BACKEND']
|
||||
- don't let aspect_ratio impact subplot size
|
||||
- implement arrowstyle for GR
|
||||
- fix bug in plotly_convert_to_datetime
|
||||
- improve missing support
|
||||
- gr: polar heatmaps
|
||||
- make sure show returns nothing
|
||||
|
||||
## 0.25.1
|
||||
- fix gr_display
|
||||
|
||||
## 0.25.0
|
||||
- Replace StaticArrays with GeometryTypes
|
||||
- Contour fixes for GR
|
||||
|
||||
## 0.24.0
|
||||
- Update to the new PyCall and PyPlot API
|
||||
- fix drawing of ticks
|
||||
- fix y label position with GR
|
||||
|
||||
## 0.23.2
|
||||
- pyplot fixes
|
||||
- Add option :tex_output_standalone to set the 'include_preamble' argument in the PGFPlots backend.
|
||||
- fix ticks
|
||||
- support plotly json mime
|
||||
- fix image axis limits
|
||||
- default to radius 0 at center for polar plots
|
||||
|
||||
## 0.23.1
|
||||
- slightly faster load time
|
||||
- fixed errant MethodError
|
||||
- fix bar plots with unicodeplots
|
||||
- better colorbars for contour
|
||||
- add volume seriestype for GR
|
||||
- fix passing a tuple to custom ticks
|
||||
- add vline to pgfplots
|
||||
- add tex output for pyplot
|
||||
- better 3d axis labels for GR
|
||||
|
||||
## 0.23.0
|
||||
- compatible with StatPlots -> StatsPlots name shift
|
||||
- fix histograms for vectors with NaN and Inf
|
||||
- change gif behaviour (remove cache-busting)
|
||||
- improved docstrings for shorthands functions
|
||||
- fix font rotation for pyplot
|
||||
- fix greyscale images for pyplot
|
||||
- clamp greyscale images with values outside 0,1
|
||||
- support keyword argument for font options
|
||||
- allow vector of markers for pyplot scatter
|
||||
|
||||
## 0.22.5
|
||||
- improve behaviour of plotlyjs backend
|
||||
|
||||
## 0.22.4
|
||||
- Add support for discrete contourf plots with GR
|
||||
|
||||
## 0.22.3
|
||||
- Fix the `showtheme` function
|
||||
|
||||
## 0.22.2
|
||||
- Allow annotations to accept a Tuple instead of the result of a text call (making it possible to specify font characteristics in recipes). E.g. `annotations = (2, 4, ("test", :right, 8, :red))` is the same as `annotations = (2, 4, text("test", :right, 8, :red))`
|
||||
|
||||
## 0.22.1
|
||||
- push PlotsDisplay just after REPLDisplay
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
name = "Plots"
|
||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
author = ["Tom Breloff (@tbreloff)"]
|
||||
version = "0.26.1"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
|
||||
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
|
||||
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
|
||||
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
|
||||
GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb"
|
||||
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
|
||||
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
|
||||
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
|
||||
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
|
||||
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
|
||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
|
||||
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
|
||||
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
|
||||
Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
|
||||
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
|
||||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
|
||||
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
|
||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||
|
||||
[compat]
|
||||
FixedPointNumbers = "≥ 0.3.0"
|
||||
GR = "≥ 0.31.0"
|
||||
PlotThemes = "≥ 0.1.3"
|
||||
PlotUtils = "≥ 0.4.1"
|
||||
RecipesBase = "≥ 0.6.0"
|
||||
StatsBase = "≥ 0.14.0"
|
||||
julia = "≥ 1.0.0"
|
||||
|
||||
[extras]
|
||||
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
|
||||
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
|
||||
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
||||
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
|
||||
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
|
||||
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
|
||||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
|
||||
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
|
||||
BinaryProvider = "b99e7846-7c00-51b0-8f62-c81ae34c0232"
|
||||
|
||||
[targets]
|
||||
test = ["BinaryProvider", "Pkg", "Test", "Random", "StatsPlots", "VisualRegressionTests", "LaTeXStrings", "Images", "ImageMagick", "RDatasets", "FileIO", "UnicodePlots"]
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#### Created by Tom Breloff (@tbreloff)
|
||||
|
||||
#### Maintained by the [JuliaPlot members](https://github.com/orgs/JuliaPlots/people)
|
||||
#### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people)
|
||||
|
||||
Plots is a plotting API and toolset. My goals with the package are:
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
julia 1.0
|
||||
|
||||
RecipesBase 0.6.0
|
||||
PlotUtils 0.4.1
|
||||
PlotThemes 0.1.3
|
||||
Reexport
|
||||
StaticArrays 0.5
|
||||
FixedPointNumbers 0.3
|
||||
Measures
|
||||
Showoff
|
||||
StatsBase 0.14.0
|
||||
JSON
|
||||
NaNMath
|
||||
Requires
|
||||
Contour
|
||||
GR 0.37.0
|
||||
+5
-3
@@ -1,13 +1,15 @@
|
||||
module Plots
|
||||
|
||||
_current_plots_version = v"0.20.6"
|
||||
_current_plots_version = v"0.26.1"
|
||||
|
||||
using Reexport
|
||||
|
||||
import StaticArrays
|
||||
import GeometryTypes
|
||||
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
|
||||
import SparseArrays: findnz
|
||||
|
||||
using FFMPEG
|
||||
|
||||
@reexport using RecipesBase
|
||||
import RecipesBase: plot, plot!, animate
|
||||
using Base.Meta
|
||||
@@ -187,7 +189,7 @@ include("backends/plotly.jl")
|
||||
include("backends/gr.jl")
|
||||
include("backends/web.jl")
|
||||
|
||||
include("shorthands.jl")
|
||||
include("shorthands.jl")
|
||||
|
||||
let PlotOrSubplot = Union{Plot, Subplot}
|
||||
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
|
||||
+14
-5
@@ -70,21 +70,21 @@ function buildanimation(animdir::AbstractString, fn::AbstractString,
|
||||
fps::Integer = 20, loop::Integer = 0,
|
||||
variable_palette::Bool=false,
|
||||
show_msg::Bool=true)
|
||||
fn = abspath(fn)
|
||||
fn = abspath(expanduser(fn))
|
||||
|
||||
if is_animated_gif
|
||||
if variable_palette
|
||||
# generate a colorpalette for each frame for highest quality, but larger filesize
|
||||
palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`)
|
||||
ffmpeg_exe(`-v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`)
|
||||
else
|
||||
# generate a colorpalette first so ffmpeg does not have to guess it
|
||||
run(`ffmpeg -v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
|
||||
ffmpeg_exe(`-v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
|
||||
# then apply the palette to get better results
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`)
|
||||
ffmpeg_exe(` -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`)
|
||||
end
|
||||
else
|
||||
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
|
||||
ffmpeg_exe(`-v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
|
||||
end
|
||||
|
||||
show_msg && @info("Saved animation to ", fn)
|
||||
@@ -103,6 +103,15 @@ function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
else
|
||||
error("Cannot show animation with extension $ext: $agif")
|
||||
end)
|
||||
return nothing
|
||||
end
|
||||
|
||||
|
||||
# Only gifs can be shown via image/gif
|
||||
Base.showable(::MIME"image/gif", agif::AnimatedGif) = file_extension(agif.filename) == "gif"
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/gif", agif::AnimatedGif)
|
||||
open(fio-> write(io, fio), agif.filename)
|
||||
end
|
||||
|
||||
|
||||
|
||||
+4
-1
@@ -49,7 +49,8 @@ const _arg_desc = KW(
|
||||
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
|
||||
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
|
||||
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
|
||||
|
||||
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
|
||||
|
||||
# plot args
|
||||
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
|
||||
:background_color => "Color Type. Base color for all backgrounds.",
|
||||
@@ -63,6 +64,7 @@ const _arg_desc = KW(
|
||||
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
|
||||
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
|
||||
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
|
||||
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.",
|
||||
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
|
||||
:dpi => "Number. Dots Per Inch of output figures",
|
||||
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
|
||||
@@ -149,4 +151,5 @@ const _arg_desc = KW(
|
||||
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
|
||||
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
|
||||
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
|
||||
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
|
||||
)
|
||||
|
||||
+24
-15
@@ -232,6 +232,7 @@ const _bar_width = 0.8
|
||||
|
||||
const _series_defaults = KW(
|
||||
:label => "AUTO",
|
||||
:colorbar_entry => true,
|
||||
:seriescolor => :auto,
|
||||
:seriesalpha => nothing,
|
||||
:seriestype => :path,
|
||||
@@ -298,6 +299,7 @@ const _plot_defaults = KW(
|
||||
:link => :none,
|
||||
:overwrite_figure => true,
|
||||
:html_output_format => :auto,
|
||||
:tex_output_standalone => false,
|
||||
:inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are
|
||||
# the parent layout and the relative bounding box of inset subplots
|
||||
:dpi => DPI, # dots per inch for images, etc
|
||||
@@ -390,6 +392,7 @@ const _axis_defaults = KW(
|
||||
:minorgrid => false,
|
||||
:showaxis => true,
|
||||
:widen => true,
|
||||
:draw_arrow => false,
|
||||
)
|
||||
|
||||
const _suppress_warnings = Set{Symbol}([
|
||||
@@ -735,6 +738,10 @@ function processMarkerArg(plotattributes::KW, arg)
|
||||
elseif allAlphas(arg)
|
||||
plotattributes[:markeralpha] = arg
|
||||
|
||||
# bool
|
||||
elseif typeof(arg) <: Bool
|
||||
plotattributes[:markershape] = arg ? :circle : :none
|
||||
|
||||
# markersize
|
||||
elseif allReals(arg)
|
||||
plotattributes[:markersize] = arg
|
||||
@@ -1023,7 +1030,7 @@ function preprocessArgs!(plotattributes::KW)
|
||||
arrow()
|
||||
elseif a in (false, nothing, :none)
|
||||
nothing
|
||||
elseif !(typeof(a) <: Arrow)
|
||||
elseif !(typeof(a) <: Arrow || typeof(a) <: AbstractArray{Arrow})
|
||||
arrow(wraptuple(a)...)
|
||||
else
|
||||
a
|
||||
@@ -1180,7 +1187,7 @@ function convertLegendValue(val::Symbol)
|
||||
:best
|
||||
elseif val in (:no, :none)
|
||||
:none
|
||||
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright)
|
||||
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright, :outertopleft, :outertop, :outerright, :outerleft, :outerbottomright, :outerbottomleft, :outerbottom)
|
||||
val
|
||||
else
|
||||
error("Invalid symbol for legend: $val")
|
||||
@@ -1508,19 +1515,19 @@ function has_black_border_for_default(st::Symbol)
|
||||
like_histogram(st) || st in (:hexbin, :bar, :shape)
|
||||
end
|
||||
|
||||
|
||||
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
|
||||
function getSeriesRGBColor(c, sp::Subplot, n::Int)
|
||||
# converts a symbol or string into a Colorant or ColorGradient
|
||||
# and assigns a color automatically
|
||||
function get_series_color(c, sp::Subplot, n::Int, seriestype)
|
||||
if c == :auto
|
||||
c = autopick(sp[:color_palette], n)
|
||||
c = like_surface(seriestype) ? cgrad() : autopick(sp[:color_palette], n)
|
||||
elseif isa(c, Int)
|
||||
c = autopick(sp[:color_palette], c)
|
||||
end
|
||||
plot_color(c)
|
||||
end
|
||||
|
||||
function getSeriesRGBColor(c::AbstractArray, sp::Subplot, n::Int)
|
||||
map(x->getSeriesRGBColor(x, sp, n), c)
|
||||
function get_series_color(c::AbstractArray, sp::Subplot, n::Int, seriestype)
|
||||
map(x->get_series_color(x, sp, n, seriestype), c)
|
||||
end
|
||||
|
||||
function ensure_gradient!(plotattributes::KW, csym::Symbol, asym::Symbol)
|
||||
@@ -1565,21 +1572,23 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot)
|
||||
end
|
||||
|
||||
# update series color
|
||||
plotattributes[:seriescolor] = getSeriesRGBColor(plotattributes[:seriescolor], sp, plotIndex)
|
||||
scolor = plotattributes[:seriescolor]
|
||||
stype = plotattributes[:seriestype]
|
||||
plotattributes[:seriescolor] = scolor = get_series_color(scolor, sp, plotIndex, stype)
|
||||
|
||||
# update other colors
|
||||
for s in (:line, :marker, :fill)
|
||||
csym, asym = Symbol(s,:color), Symbol(s,:alpha)
|
||||
plotattributes[csym] = if plotattributes[csym] == :auto
|
||||
plot_color(if has_black_border_for_default(plotattributes[:seriestype]) && s == :line
|
||||
plot_color(if has_black_border_for_default(stype) && s == :line
|
||||
sp[:foreground_color_subplot]
|
||||
else
|
||||
plotattributes[:seriescolor]
|
||||
scolor
|
||||
end)
|
||||
elseif plotattributes[csym] == :match
|
||||
plot_color(plotattributes[:seriescolor])
|
||||
plot_color(scolor)
|
||||
else
|
||||
getSeriesRGBColor(plotattributes[csym], sp, plotIndex)
|
||||
get_series_color(plotattributes[csym], sp, plotIndex, stype)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1587,9 +1596,9 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot)
|
||||
plotattributes[:markerstrokecolor] = if plotattributes[:markerstrokecolor] == :match
|
||||
plot_color(sp[:foreground_color_subplot])
|
||||
elseif plotattributes[:markerstrokecolor] == :auto
|
||||
getSeriesRGBColor(plotattributes[:markercolor], sp, plotIndex)
|
||||
get_series_color(plotattributes[:markercolor], sp, plotIndex, stype)
|
||||
else
|
||||
getSeriesRGBColor(plotattributes[:markerstrokecolor], sp, plotIndex)
|
||||
get_series_color(plotattributes[:markerstrokecolor], sp, plotIndex, stype)
|
||||
end
|
||||
|
||||
# if marker_z, fill_z or line_z are set, ensure we have a gradient
|
||||
|
||||
+55
-27
@@ -117,7 +117,7 @@ end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
Base.show(io::IO, axis::Axis) = dumpdict(axis.plotattributes, "Axis", true)
|
||||
Base.show(io::IO, axis::Axis) = dumpdict(io, axis.plotattributes, "Axis", true)
|
||||
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.plotattributes, k)
|
||||
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v, ks...)
|
||||
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k)
|
||||
@@ -152,8 +152,8 @@ scalefunc(scale::Symbol) = x -> get(_scale_funcs, scale, identity)(Float64(x))
|
||||
invscalefunc(scale::Symbol) = x -> get(_inv_scale_funcs, scale, identity)(Float64(x))
|
||||
labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string)
|
||||
|
||||
function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
|
||||
amin,amax = axis_limits(axis)
|
||||
function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
|
||||
amin, amax = axis_limits(sp, axis[:letter])
|
||||
|
||||
# scale the limits
|
||||
scale = axis[:scale]
|
||||
@@ -238,9 +238,9 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
|
||||
end
|
||||
|
||||
# return (continuous_values, discrete_values) for the ticks on this axis
|
||||
function get_ticks(axis::Axis)
|
||||
function get_ticks(sp::Subplot, axis::Axis)
|
||||
ticks = _transform_ticks(axis[:ticks])
|
||||
ticks in (nothing, false) && return nothing
|
||||
ticks in (:none, nothing, false) && return nothing
|
||||
|
||||
# treat :native ticks as :auto
|
||||
ticks = ticks == :native ? :auto : ticks
|
||||
@@ -251,7 +251,7 @@ function get_ticks(axis::Axis)
|
||||
# discrete ticks...
|
||||
n = length(dvals)
|
||||
rng = if ticks == :auto
|
||||
Int[round(Int,i) for i in range(1, stop=n, length=15)]
|
||||
Int[round(Int,i) for i in range(1, stop=n, length=min(n,15))]
|
||||
else # if ticks == :all
|
||||
1:n
|
||||
end
|
||||
@@ -261,7 +261,7 @@ function get_ticks(axis::Axis)
|
||||
(collect(0:pi/4:7pi/4), string.(0:45:315))
|
||||
else
|
||||
# compute optimal ticks and labels
|
||||
optimal_ticks_and_labels(axis)
|
||||
optimal_ticks_and_labels(sp, axis)
|
||||
end
|
||||
elseif typeof(ticks) <: Union{AVec, Int}
|
||||
if !isempty(dvals) && typeof(ticks) <: Int
|
||||
@@ -269,7 +269,7 @@ function get_ticks(axis::Axis)
|
||||
axis[:continuous_values][rng], dvals[rng]
|
||||
else
|
||||
# override ticks, but get the labels
|
||||
optimal_ticks_and_labels(axis, ticks)
|
||||
optimal_ticks_and_labels(sp, axis, ticks)
|
||||
end
|
||||
elseif typeof(ticks) <: NTuple{2, Any}
|
||||
# assuming we're passed (ticks, labels)
|
||||
@@ -286,12 +286,12 @@ _transform_ticks(ticks) = ticks
|
||||
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
|
||||
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
|
||||
|
||||
function get_minor_ticks(axis,ticks)
|
||||
axis[:minorticks] in (nothing, false) && !axis[:minorgrid] && return nothing
|
||||
function get_minor_ticks(sp, axis, ticks)
|
||||
axis[:minorticks] in (:none, nothing, false) && !axis[:minorgrid] && return nothing
|
||||
ticks = ticks[1]
|
||||
length(ticks) < 2 && return nothing
|
||||
|
||||
amin, amax = axis_limits(axis)
|
||||
amin, amax = axis_limits(sp, axis[:letter])
|
||||
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
|
||||
if length(ticks) > 2
|
||||
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
|
||||
@@ -479,11 +479,13 @@ function round_limits(amin,amax)
|
||||
end
|
||||
|
||||
# using the axis extrema and limit overrides, return the min/max value for this axis
|
||||
function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis))
|
||||
function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(letter, :axis)]), consider_aspect = true)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
ex = axis[:extrema]
|
||||
amin, amax = ex.emin, ex.emax
|
||||
lims = axis[:lims]
|
||||
if (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
|
||||
has_user_lims = (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
|
||||
if has_user_lims
|
||||
if isfinite(lims[1])
|
||||
amin = lims[1]
|
||||
end
|
||||
@@ -497,12 +499,12 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
if !isfinite(amin) && !isfinite(amax)
|
||||
amin, amax = 0.0, 1.0
|
||||
end
|
||||
if ispolar(axis.sps[1])
|
||||
amin, amax = if ispolar(axis.sps[1])
|
||||
if axis[:letter] == :x
|
||||
amin, amax = 0, 2pi
|
||||
elseif lims == :auto
|
||||
#widen max radius so ticks dont overlap with theta axis
|
||||
amin, amax + 0.1 * abs(amax - amin)
|
||||
0, amax + 0.1 * abs(amax - amin)
|
||||
else
|
||||
amin, amax
|
||||
end
|
||||
@@ -513,6 +515,32 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
else
|
||||
amin, amax
|
||||
end
|
||||
|
||||
if !has_user_lims && consider_aspect && letter in (:x, :y) && !(sp[:aspect_ratio] in (:none, :auto) || is3d(:sp))
|
||||
aspect_ratio = isa(sp[:aspect_ratio], Number) ? sp[:aspect_ratio] : 1
|
||||
plot_ratio = height(plotarea(sp)) / width(plotarea(sp))
|
||||
dist = amax - amin
|
||||
|
||||
if letter == :x
|
||||
yamin, yamax = axis_limits(sp, :y, default_should_widen(sp[:yaxis]), false)
|
||||
ydist = yamax - yamin
|
||||
axis_ratio = aspect_ratio * ydist / dist
|
||||
factor = axis_ratio / plot_ratio
|
||||
else
|
||||
xamin, xamax = axis_limits(sp, :x, default_should_widen(sp[:xaxis]), false)
|
||||
xdist = xamax - xamin
|
||||
axis_ratio = aspect_ratio * dist / xdist
|
||||
factor = plot_ratio / axis_ratio
|
||||
end
|
||||
|
||||
if factor > 1
|
||||
center = (amin + amax) / 2
|
||||
amin = center + factor * (amin - center)
|
||||
amax = center + factor * (amax - center)
|
||||
end
|
||||
end
|
||||
|
||||
return amin, amax
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -586,12 +614,12 @@ end
|
||||
# compute the line segments which should be drawn for this axis
|
||||
function axis_drawing_info(sp::Subplot)
|
||||
xaxis, yaxis = sp[:xaxis], sp[:yaxis]
|
||||
xmin, xmax = axis_limits(xaxis)
|
||||
ymin, ymax = axis_limits(yaxis)
|
||||
xticks = get_ticks(xaxis)
|
||||
yticks = get_ticks(yaxis)
|
||||
xminorticks = get_minor_ticks(xaxis,xticks)
|
||||
yminorticks = get_minor_ticks(yaxis,yticks)
|
||||
xmin, xmax = axis_limits(sp, :x)
|
||||
ymin, ymax = axis_limits(sp, :y)
|
||||
xticks = get_ticks(sp, xaxis)
|
||||
yticks = get_ticks(sp, yaxis)
|
||||
xminorticks = get_minor_ticks(sp, xaxis, xticks)
|
||||
yminorticks = get_minor_ticks(sp, yaxis, yticks)
|
||||
xaxis_segs = Segments(2)
|
||||
yaxis_segs = Segments(2)
|
||||
xtick_segs = Segments(2)
|
||||
@@ -614,14 +642,14 @@ function axis_drawing_info(sp::Subplot)
|
||||
end
|
||||
push!(xaxis_segs, (xmin, y1), (xmax, y1))
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && !(xticks in (nothing,false)) && length(xticks) > 1
|
||||
if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && 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, y2), (xmax, y2)) # top spine
|
||||
end
|
||||
if !(xaxis[:ticks] in (nothing, false))
|
||||
if !(xaxis[:ticks] in (:none, nothing, false))
|
||||
f = scalefunc(yaxis[:scale])
|
||||
invf = invscalefunc(yaxis[:scale])
|
||||
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
|
||||
@@ -642,7 +670,7 @@ function axis_drawing_info(sp::Subplot)
|
||||
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
|
||||
end
|
||||
end
|
||||
if !(xaxis[:minorticks] in (nothing, false)) || xaxis[:minorgrid]
|
||||
if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid]
|
||||
f = scalefunc(yaxis[:scale])
|
||||
invf = invscalefunc(yaxis[:scale])
|
||||
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
|
||||
@@ -675,14 +703,14 @@ function axis_drawing_info(sp::Subplot)
|
||||
end
|
||||
push!(yaxis_segs, (x1, ymin), (x1, ymax))
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && !(yticks in (nothing,false)) && length(yticks) > 1
|
||||
if sp[:framestyle] == :origin && !(yticks in (:none, nothing,false)) && length(yticks) > 1
|
||||
showticks = yticks[1] .!= 0
|
||||
yticks = (yticks[1][showticks], yticks[2][showticks])
|
||||
end
|
||||
end
|
||||
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin), (x2, ymax)) # right spine
|
||||
end
|
||||
if !(yaxis[:ticks] in (nothing, false))
|
||||
if !(yaxis[:ticks] in (:none, nothing, false))
|
||||
f = scalefunc(xaxis[:scale])
|
||||
invf = invscalefunc(xaxis[:scale])
|
||||
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
|
||||
@@ -703,7 +731,7 @@ function axis_drawing_info(sp::Subplot)
|
||||
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
|
||||
end
|
||||
end
|
||||
if !(yaxis[:minorticks] in (nothing, false)) || yaxis[:minorgrid]
|
||||
if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid]
|
||||
f = scalefunc(xaxis[:scale])
|
||||
invf = invscalefunc(xaxis[:scale])
|
||||
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
|
||||
|
||||
+12
-16
@@ -75,8 +75,8 @@ end
|
||||
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
|
||||
|
||||
# account for the size/length/rotation of tick labels
|
||||
function tick_padding(axis::Axis)
|
||||
ticks = get_ticks(axis)
|
||||
function tick_padding(sp::Subplot, axis::Axis)
|
||||
ticks = get_ticks(sp, axis)
|
||||
if ticks == nothing
|
||||
0mm
|
||||
else
|
||||
@@ -106,10 +106,10 @@ end
|
||||
# to fit ticks, tick labels, guides, colorbars, etc.
|
||||
function _update_min_padding!(sp::Subplot)
|
||||
# TODO: something different when `is3d(sp) == true`
|
||||
leftpad = tick_padding(sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
|
||||
leftpad = tick_padding(sp, sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
|
||||
toppad = sp[:top_margin] + title_padding(sp)
|
||||
rightpad = sp[:right_margin]
|
||||
bottompad = tick_padding(sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
|
||||
bottompad = tick_padding(sp, sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
|
||||
|
||||
# switch them?
|
||||
if sp[:xaxis][:mirror]
|
||||
@@ -143,12 +143,7 @@ function _pick_default_backend()
|
||||
if env_default != ""
|
||||
sym = Symbol(lowercase(env_default))
|
||||
if sym in _backends
|
||||
if sym in _initialized_backends
|
||||
backend(sym)
|
||||
else
|
||||
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
|
||||
_fallback_default_backend()
|
||||
end
|
||||
backend(sym)
|
||||
else
|
||||
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t" *
|
||||
join(sort(_backends), "\n\t"))
|
||||
@@ -332,7 +327,7 @@ const _gr_attr = merge_with_base_supported([
|
||||
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
|
||||
:guidefontrotation, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
@@ -351,7 +346,7 @@ const _gr_attr = merge_with_base_supported([
|
||||
const _gr_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :path3d, :scatter3d, :surface, :wireframe,
|
||||
:contour, :path3d, :scatter3d, :surface, :wireframe, :volume,
|
||||
:shape
|
||||
]
|
||||
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
@@ -386,7 +381,7 @@ const _plotly_attr = merge_with_base_supported([
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :gridalpha, :gridlinewidth,
|
||||
:legend, :colorbar, :colorbar_title,
|
||||
:legend, :colorbar, :colorbar_title, :colorbar_entry,
|
||||
:marker_z, :fill_z, :line_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
@@ -417,6 +412,8 @@ const _plotly_marker = [
|
||||
]
|
||||
const _plotly_scale = [:identity, :log10]
|
||||
|
||||
defaultOutputFormat(plt::Plot{Plots.PlotlyBackend}) = "html"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pgfplots
|
||||
|
||||
@@ -457,7 +454,7 @@ const _pgfplots_attr = merge_with_base_supported([
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -509,7 +506,7 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
@@ -522,7 +519,6 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
:stride,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
|
||||
+444
-198
File diff suppressed because it is too large
Load Diff
@@ -294,8 +294,8 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
|
||||
|
||||
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
|
||||
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
|
||||
xmin, xmax = axis_limits(xaxis)
|
||||
ymin, ymax = axis_limits(yaxis)
|
||||
xmin, xmax = axis_limits(sp, :x)
|
||||
ymin, ymax = axis_limits(sp, :y)
|
||||
if ispolar(sp)
|
||||
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
|
||||
rmax = NaNMath.max(abs(ymin), abs(ymax))
|
||||
|
||||
@@ -26,7 +26,8 @@ const _pgfplots_markers = KW(
|
||||
:star6 => "asterisk",
|
||||
:diamond => "diamond*",
|
||||
:pentagon => "pentagon*",
|
||||
:hline => "-"
|
||||
:hline => "-",
|
||||
:vline => "|"
|
||||
)
|
||||
|
||||
const _pgfplots_legend_pos = KW(
|
||||
@@ -170,7 +171,7 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
elseif ispolar(sp)
|
||||
theta, r = filter_radial_data(plotattributes[:x], plotattributes[:y], axis_limits(sp[:yaxis]))
|
||||
theta, r = plotattributes[:x], plotattributes[:y]
|
||||
rad2deg.(theta), r
|
||||
else
|
||||
plotattributes[:x], plotattributes[:y]
|
||||
@@ -360,13 +361,13 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# limits
|
||||
# TODO: support zlims
|
||||
if letter != :z
|
||||
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
|
||||
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||
ticks = get_ticks(axis)
|
||||
ticks = get_ticks(sp, axis)
|
||||
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
|
||||
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
|
||||
@@ -398,8 +399,12 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# framestyle
|
||||
if framestyle in (:axes, :origin)
|
||||
axispos = framestyle == :axes ? "left" : "middle"
|
||||
# the * after lines disables the arrows at the axes
|
||||
push!(style, string("axis lines* = ", axispos))
|
||||
if axis[:draw_arrow]
|
||||
push!(style, string("axis ", letter, " line = ", axispos))
|
||||
else
|
||||
# the * after line disables the arrow at the axis
|
||||
push!(style, string("axis ", letter, " line* = ", axispos))
|
||||
end
|
||||
end
|
||||
|
||||
if framestyle == :zerolines
|
||||
@@ -563,7 +568,7 @@ end
|
||||
|
||||
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
|
||||
fn = tempname()*".tex"
|
||||
PGFPlots.save(fn, backend_object(plt), include_preamble=false)
|
||||
PGFPlots.save(fn, backend_object(plt), include_preamble=plt.attr[:tex_output_standalone])
|
||||
write(io, read(open(fn), String))
|
||||
end
|
||||
|
||||
|
||||
+33
-26
@@ -114,8 +114,8 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
|
||||
if aspect_ratio == :equal
|
||||
aspect_ratio = 1.0
|
||||
end
|
||||
xmin,xmax = axis_limits(sp[:xaxis])
|
||||
ymin,ymax = axis_limits(sp[:yaxis])
|
||||
xmin,xmax = axis_limits(sp, :x)
|
||||
ymin,ymax = axis_limits(sp, :y)
|
||||
want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio
|
||||
parea_ratio = width(plotarea) / height(plotarea)
|
||||
if want_ratio > parea_ratio
|
||||
@@ -174,7 +174,7 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
|
||||
|
||||
ax[:tickangle] = -axis[:rotation]
|
||||
ax[:type] = plotly_scale(axis[:scale])
|
||||
lims = axis_limits(axis)
|
||||
lims = axis_limits(sp, letter)
|
||||
|
||||
if axis[:ticks] != :native || axis[:lims] != :auto
|
||||
ax[:range] = map(scalefunc(axis[:scale]), lims)
|
||||
@@ -186,14 +186,9 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
|
||||
ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
|
||||
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
|
||||
|
||||
# flip
|
||||
if axis[:flip]
|
||||
ax[:range] = reverse(ax[:range])
|
||||
end
|
||||
|
||||
# ticks
|
||||
if axis[:ticks] != :native
|
||||
ticks = get_ticks(axis)
|
||||
ticks = get_ticks(sp, axis)
|
||||
ttype = ticksType(ticks)
|
||||
if ttype == :ticks
|
||||
ax[:tickmode] = "array"
|
||||
@@ -208,20 +203,24 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
|
||||
ax[:showgrid] = false
|
||||
end
|
||||
|
||||
# flip
|
||||
if axis[:flip]
|
||||
ax[:range] = reverse(ax[:range])
|
||||
end
|
||||
|
||||
ax
|
||||
end
|
||||
|
||||
function plotly_polaraxis(axis::Axis)
|
||||
function plotly_polaraxis(sp::Subplot, axis::Axis)
|
||||
ax = KW(
|
||||
:visible => axis[:showaxis],
|
||||
:showline => axis[:grid],
|
||||
)
|
||||
|
||||
if axis[:letter] == :x
|
||||
ax[:range] = rad2deg.(axis_limits(axis))
|
||||
ax[:range] = rad2deg.(axis_limits(sp, :x))
|
||||
else
|
||||
ax[:range] = axis_limits(axis)
|
||||
ax[:range] = axis_limits(sp, :y)
|
||||
ax[:orientation] = -90
|
||||
end
|
||||
|
||||
@@ -284,8 +283,8 @@ function plotly_layout(plt::Plot)
|
||||
),
|
||||
)
|
||||
elseif ispolar(sp)
|
||||
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
|
||||
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
|
||||
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis])
|
||||
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis])
|
||||
else
|
||||
plotattributes_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
|
||||
# don't allow yaxis to be reupdated/reanchored in a linked subplot
|
||||
@@ -348,14 +347,14 @@ function plotly_layout(plt::Plot)
|
||||
end
|
||||
|
||||
function plotly_layout_json(plt::Plot)
|
||||
JSON.json(plotly_layout(plt))
|
||||
JSON.json(plotly_layout(plt), 4)
|
||||
end
|
||||
|
||||
|
||||
function plotly_colorscale(grad::ColorGradient, α)
|
||||
[[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in 1:length(grad.colors)]
|
||||
end
|
||||
plotly_colorscale(c, α) = plotly_colorscale(cgrad(alpha=α), α)
|
||||
plotly_colorscale(c::Colorant,α) = plotly_colorscale(_as_gradient(c),α)
|
||||
function plotly_colorscale(c::AbstractVector{<:RGBA}, α)
|
||||
if length(c) == 1
|
||||
return [[0.0, rgba_string(plot_color(c[1], α))], [1.0, rgba_string(plot_color(c[1], α))]]
|
||||
@@ -437,7 +436,7 @@ plotly_native_data(axis::Axis, a::Surface) = Surface(plotly_native_data(axis, a.
|
||||
|
||||
function plotly_convert_to_datetime(x::AbstractArray, formatter::Function)
|
||||
if formatter == datetimeformatter
|
||||
map(xi -> replace(formatter(xi), "T", " "), x)
|
||||
map(xi -> replace(formatter(xi), "T" => " "), x)
|
||||
elseif formatter == dateformatter
|
||||
map(xi -> string(formatter(xi), " 00:00:00"), x)
|
||||
elseif formatter == timeformatter
|
||||
@@ -507,13 +506,13 @@ function plotly_series(plt::Plot, series::Series)
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
|
||||
elseif st == :contour
|
||||
filled = isfilledcontour(series)
|
||||
plotattributes_out[:type] = "contour"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
# plotattributes_out[:showscale] = series[:colorbar] != :none
|
||||
plotattributes_out[:ncontours] = series[:levels]
|
||||
plotattributes_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
|
||||
plotattributes_out[:ncontours] = series[:levels] + 2
|
||||
plotattributes_out[:contours] = KW(:coloring => filled ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
|
||||
plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
plotattributes_out[:showscale] = hascolorbar(sp)
|
||||
plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series)
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
plotattributes_out[:type] = "surface"
|
||||
@@ -775,7 +774,7 @@ end
|
||||
function plotly_polar!(plotattributes_out::KW, series::Series)
|
||||
# convert polar plots x/y to theta/radius
|
||||
if ispolar(series[:subplot])
|
||||
theta, r = filter_radial_data(pop!(plotattributes_out, :x), pop!(plotattributes_out, :y), axis_limits(series[:subplot][:yaxis]))
|
||||
theta, r = pop!(plotattributes_out, :x), pop!(plotattributes_out, :y)
|
||||
plotattributes_out[:t] = rad2deg.(theta)
|
||||
plotattributes_out[:r] = r
|
||||
end
|
||||
@@ -801,7 +800,7 @@ function plotly_series(plt::Plot)
|
||||
end
|
||||
|
||||
# get json string for a list of dictionaries, each representing the series params
|
||||
plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt))
|
||||
plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt), 4)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@@ -823,8 +822,6 @@ function html_head(plt::Plot{PlotlyBackend})
|
||||
""")
|
||||
ijulia_initialized[] = true
|
||||
end
|
||||
# IJulia just needs one initialization
|
||||
isijulia() && return ""
|
||||
return "<script src=$(repr(plotly))></script>"
|
||||
end
|
||||
|
||||
@@ -854,11 +851,21 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{PlotlyBackend})
|
||||
data = []
|
||||
for series in plot.series_list
|
||||
append!(data, plotly_series(plot, series))
|
||||
end
|
||||
layout = plotly_layout(plot)
|
||||
JSON.print(io, Dict(:data => data, :layout => layout))
|
||||
end
|
||||
|
||||
|
||||
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
write(io, standalone_html(plt))
|
||||
end
|
||||
|
||||
|
||||
function _display(plt::Plot{PlotlyBackend})
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
|
||||
@@ -55,6 +55,11 @@ _show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(
|
||||
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="pdf")
|
||||
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="eps")
|
||||
|
||||
function _show(io::IO, m::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend})
|
||||
show(io, m, plt.o)
|
||||
end
|
||||
|
||||
|
||||
function write_temp_html(plt::Plot{PlotlyJSBackend})
|
||||
filename = string(tempname(), ".html")
|
||||
savefig(plt, filename)
|
||||
|
||||
+214
-160
@@ -21,7 +21,7 @@ pyfont = PyPlot.pyimport("matplotlib.font_manager")
|
||||
pyticker = PyPlot.pyimport("matplotlib.ticker")
|
||||
pycmap = PyPlot.pyimport("matplotlib.cm")
|
||||
pynp = PyPlot.pyimport("numpy")
|
||||
pynp["seterr"](invalid="ignore")
|
||||
pynp."seterr"(invalid="ignore")
|
||||
pytransforms = PyPlot.pyimport("matplotlib.transforms")
|
||||
pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
pyart3d = PyPlot.art3D
|
||||
@@ -34,6 +34,11 @@ else
|
||||
:set_facecolor
|
||||
end
|
||||
|
||||
# PyCall API changes in v1.90.0
|
||||
if !isdefined(PyCall, :_setproperty!)
|
||||
@warn "Plots no longer supports PyCall < 1.90.0 and PyPlot < 2.8.0. Either update PyCall and PyPlot or pin Plots to a version <= 0.23.2."
|
||||
end
|
||||
|
||||
|
||||
# # convert colorant to 4-tuple RGBA
|
||||
# py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
|
||||
@@ -64,17 +69,17 @@ py_color(c::Colorant, α) = py_color(plot_color(c, α))
|
||||
|
||||
function py_colormap(grad::ColorGradient)
|
||||
pyvals = [(z, py_color(grad[z])) for z in grad.values]
|
||||
cm = pycolors["LinearSegmentedColormap"][:from_list]("tmp", pyvals)
|
||||
cm[:set_bad](color=(0,0,0,0.0), alpha=0.0)
|
||||
cm = pycolors."LinearSegmentedColormap"."from_list"("tmp", pyvals)
|
||||
cm."set_bad"(color=(0,0,0,0.0), alpha=0.0)
|
||||
cm
|
||||
end
|
||||
py_colormap(c) = py_colormap(cgrad())
|
||||
py_colormap(c::Colorant) = py_colormap(_as_gradient(c))
|
||||
|
||||
|
||||
function py_shading(c, z)
|
||||
cmap = py_colormap(c)
|
||||
ls = pycolors["LightSource"](270,45)
|
||||
ls[:shade](z, cmap, vert_exag=0.1, blend_mode="soft")
|
||||
ls = pycolors."LightSource"(270,45)
|
||||
ls."shade"(z, cmap, vert_exag=0.1, blend_mode="soft")
|
||||
end
|
||||
|
||||
# get the style (solid, dashed, etc)
|
||||
@@ -97,7 +102,7 @@ function py_marker(marker::Shape)
|
||||
mat[i,2] = y[i]
|
||||
end
|
||||
mat[n+1,:] = mat[1,:]
|
||||
pypath["Path"](mat)
|
||||
pypath."Path"(mat)
|
||||
end
|
||||
|
||||
const _path_MOVETO = UInt8(1)
|
||||
@@ -182,7 +187,7 @@ end
|
||||
# end
|
||||
|
||||
function get_locator_and_formatter(vals::AVec)
|
||||
pyticker["FixedLocator"](1:length(vals)), pyticker["FixedFormatter"](vals)
|
||||
pyticker."FixedLocator"(1:length(vals)), pyticker."FixedFormatter"(vals)
|
||||
end
|
||||
|
||||
function add_pyfixedformatter(cbar, vals::AVec)
|
||||
@@ -204,20 +209,22 @@ end
|
||||
|
||||
function py_mask_nans(z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
PyCall.pycall(pynp."ma"."masked_invalid", Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
|
||||
x, y = series[:x], series[:y]
|
||||
nx, ny = length(x), length(y)
|
||||
if !isa(get(series.plotattributes, :z, nothing), Surface) && nx != ny
|
||||
if nx < ny
|
||||
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
else
|
||||
series[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
if series[:x] != nothing
|
||||
x, y = series[:x], series[:y]
|
||||
nx, ny = length(x), length(y)
|
||||
if !isa(get(series.plotattributes, :z, nothing), Surface) && nx != ny
|
||||
if nx < ny
|
||||
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
else
|
||||
series[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -248,26 +255,28 @@ py_fillcolormap(series::Series) = py_colormap(series[:fillcolor])
|
||||
# Figure utils -- F*** matplotlib for making me work so hard to figure this crap out
|
||||
|
||||
# the drawing surface
|
||||
py_canvas(fig) = fig[:canvas]
|
||||
py_canvas(fig) = fig."canvas"
|
||||
|
||||
# the object controlling draw commands
|
||||
py_renderer(fig) = py_canvas(fig)[:get_renderer]()
|
||||
py_renderer(fig) = py_canvas(fig)."get_renderer"()
|
||||
|
||||
# draw commands... paint the screen (probably updating internals too)
|
||||
py_drawfig(fig) = fig[:draw](py_renderer(fig))
|
||||
py_drawfig(fig) = fig."draw"(py_renderer(fig))
|
||||
# py_drawax(ax) = ax[:draw](py_renderer(ax[:get_figure]()))
|
||||
|
||||
# get a vector [left, right, bottom, top] in PyPlot coords (origin is bottom-left!)
|
||||
py_extents(obj) = obj[:get_window_extent]()[:get_points]()
|
||||
py_extents(obj) = obj."get_window_extent"()."get_points"()
|
||||
|
||||
|
||||
# compute a bounding box (with origin top-left), however pyplot gives coords with origin bottom-left
|
||||
function py_bbox(obj)
|
||||
fl, fr, fb, ft = py_extents(obj[:get_figure]())
|
||||
fl, fr, fb, ft = py_extents(obj."get_figure"())
|
||||
l, r, b, t = py_extents(obj)
|
||||
BoundingBox(l*px, (ft-t)*px, (r-l)*px, (t-b)*px)
|
||||
end
|
||||
|
||||
py_bbox(::Nothing) = BoundingBox(0mm, 0mm)
|
||||
|
||||
# get the bounding box of the union of the objects
|
||||
function py_bbox(v::AVec)
|
||||
bbox_union = defaultbox
|
||||
@@ -279,13 +288,13 @@ end
|
||||
|
||||
# bounding box: union of axis tick labels
|
||||
function py_bbox_ticks(ax, letter)
|
||||
labels = ax[Symbol("get_"*letter*"ticklabels")]()
|
||||
labels = getproperty(ax, Symbol("get_"*letter*"ticklabels"))()
|
||||
py_bbox(labels)
|
||||
end
|
||||
|
||||
# bounding box: axis guide
|
||||
function py_bbox_axislabel(ax, letter)
|
||||
pyaxis_label = ax[Symbol("get_"*letter*"axis")]()[:label]
|
||||
pyaxis_label = getproperty(ax, Symbol("get_"*letter*"axis"))().label
|
||||
py_bbox(pyaxis_label)
|
||||
end
|
||||
|
||||
@@ -301,11 +310,14 @@ end
|
||||
function py_bbox_title(ax)
|
||||
bb = defaultbox
|
||||
for s in (:title, :_left_title, :_right_title)
|
||||
bb = bb + py_bbox(ax[s])
|
||||
bb = bb + py_bbox(getproperty(ax, s))
|
||||
end
|
||||
bb
|
||||
end
|
||||
|
||||
# bounding box: legend
|
||||
py_bbox_legend(ax) = py_bbox(ax."get_legend"())
|
||||
|
||||
function py_thickness_scale(plt::Plot{PyPlotBackend}, ptsz)
|
||||
ptsz * plt[:thickness_scaling]
|
||||
end
|
||||
@@ -339,7 +351,7 @@ function py_init_subplot(plt::Plot{PyPlotBackend}, sp::Subplot{PyPlotBackend})
|
||||
proj = (proj in (nothing,:none) ? nothing : string(proj))
|
||||
|
||||
# add a new axis, and force it to create a new one by setting a distinct label
|
||||
ax = fig[:add_axes](
|
||||
ax = fig."add_axes"(
|
||||
[0,0,1,1],
|
||||
label = string(gensym()),
|
||||
projection = proj
|
||||
@@ -371,6 +383,18 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
elseif st == :shape
|
||||
x, y = shape_data(series)
|
||||
end
|
||||
|
||||
if ispolar(series)
|
||||
# make negative radii positive and flip the angle
|
||||
# (PyPlot ignores negative radii)
|
||||
for i in eachindex(y)
|
||||
if y[i] < 0
|
||||
y[i] = -y[i]
|
||||
x[i] -= π
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xyargs = (st in _3dTypes ? (x,y,z) : (x,y))
|
||||
|
||||
# handle zcolor and get c/cmap
|
||||
@@ -440,10 +464,10 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# push!(handles, handle)
|
||||
# else
|
||||
for (i, rng) in enumerate(iter_segments(series))
|
||||
handle = ax[:plot]((arg[rng] for arg in xyargs)...;
|
||||
handle = ax."plot"((arg[rng] for arg in xyargs)...;
|
||||
label = i == 1 ? series[:label] : "",
|
||||
zorder = series[:series_plotindex],
|
||||
color = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
|
||||
color = py_color(single_color(get_linecolor(series, clims, i)), get_linealpha(series, i)),
|
||||
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
|
||||
linestyle = py_linestyle(st, get_linestyle(series, i)),
|
||||
solid_capstyle = "round",
|
||||
@@ -468,7 +492,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
:linestyle => py_linestyle(st, get_linestyle(series)),
|
||||
)
|
||||
add_arrows(x, y) do xyprev, xy
|
||||
ax[:annotate]("",
|
||||
ax."annotate"("",
|
||||
xytext = (0.001xyprev[1] + 0.999xy[1], 0.001xyprev[2] + 0.999xy[2]),
|
||||
xy = xy,
|
||||
arrowprops = arrowprops,
|
||||
@@ -514,7 +538,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
for i=1:length(y)
|
||||
extrakw[:c] = _cycle(markercolor, i)
|
||||
|
||||
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)),
|
||||
@@ -553,7 +577,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
continue
|
||||
end
|
||||
|
||||
push!(handle, ax[:scatter](cur_x_list, cur_y_list;
|
||||
push!(handle, ax."scatter"(cur_x_list, cur_y_list;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = prev_marker,
|
||||
@@ -574,7 +598,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if !isempty(cur_color_list)
|
||||
push!(handle, ax[:scatter](cur_x_list, cur_y_list;
|
||||
push!(handle, ax."scatter"(cur_x_list, cur_y_list;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = prev_marker,
|
||||
@@ -589,7 +613,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
push!(handles, handle)
|
||||
else
|
||||
# do a normal scatter plot
|
||||
handle = ax[:scatter](xyargs...;
|
||||
handle = ax."scatter"(xyargs...;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = py_marker(series[:markershape]),
|
||||
@@ -603,7 +627,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :hexbin
|
||||
handle = ax[:hexbin](x, y;
|
||||
handle = ax."hexbin"(x, y;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
gridsize = series[:bins],
|
||||
@@ -635,7 +659,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
# contour lines
|
||||
handle = ax[:contour](x, y, z, levelargs...;
|
||||
handle = ax."contour"(x, y, z, levelargs...;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
linewidths = py_thickness_scale(plt, series[:linewidth]),
|
||||
@@ -643,13 +667,13 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw...
|
||||
)
|
||||
if series[:contour_labels] == true
|
||||
PyPlot.clabel(handle, handle[:levels])
|
||||
PyPlot."clabel"(handle, handle.levels)
|
||||
end
|
||||
push!(handles, handle)
|
||||
|
||||
# contour fills
|
||||
if series[:fillrange] != nothing
|
||||
handle = ax[:contourf](x, y, z, levelargs...;
|
||||
handle = ax."contourf"(x, y, z, levelargs...;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
extrakw...
|
||||
@@ -675,7 +699,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw[:cmap] = py_fillcolormap(series)
|
||||
end
|
||||
end
|
||||
handle = ax[st == :surface ? :plot_surface : :plot_wireframe](x, y, z;
|
||||
handle = getproperty(ax, st == :surface ? :plot_surface : :plot_wireframe)(x, y, z;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
rstride = series[:stride][1],
|
||||
@@ -690,7 +714,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
if series[:contours]
|
||||
for (zdir,mat) in (("x",x), ("y",y), ("z",z))
|
||||
offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat)
|
||||
handle = ax[:contourf](x, y, z, levelargs...;
|
||||
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
|
||||
@@ -702,7 +726,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
elseif typeof(z) <: AbstractVector
|
||||
# tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots)
|
||||
handle = ax[:plot_trisurf](x, y, z;
|
||||
handle = ax."plot_trisurf"(x, y, z;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
cmap = py_fillcolormap(series),
|
||||
@@ -727,7 +751,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
else
|
||||
z # hopefully it's in a data format that will "just work" with imshow
|
||||
end
|
||||
handle = ax[:imshow](z;
|
||||
handle = ax."imshow"(z;
|
||||
zorder = series[:series_plotindex],
|
||||
cmap = py_colormap(cgrad([:black, :white])),
|
||||
vmin = 0.0,
|
||||
@@ -737,7 +761,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
push!(handles, handle)
|
||||
|
||||
# expand extrema... handle is AxesImage object
|
||||
xmin, xmax, ymax, ymin = handle[:get_extent]()
|
||||
xmin, xmax, ymax, ymin = handle."get_extent"()
|
||||
expand_extrema!(sp, xmin, xmax, ymin, ymax)
|
||||
# sp[:yaxis].series[:flip] = true
|
||||
end
|
||||
@@ -752,7 +776,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
discrete_colorbar_values = dvals
|
||||
end
|
||||
|
||||
handle = ax[:pcolormesh](x, y, py_mask_nans(z);
|
||||
handle = ax."pcolormesh"(x, y, py_mask_nans(z);
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
cmap = py_fillcolormap(series),
|
||||
@@ -767,8 +791,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = []
|
||||
for (i, rng) in enumerate(iter_segments(series))
|
||||
if length(rng) > 1
|
||||
path = pypath["Path"](hcat(x[rng], y[rng]))
|
||||
patches = pypatches["PathPatch"](
|
||||
path = pypath."Path"(hcat(x[rng], y[rng]))
|
||||
patches = pypatches."PathPatch"(
|
||||
path;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
@@ -778,14 +802,14 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
linestyle = py_linestyle(st, get_linestyle(series, i)),
|
||||
fill = true
|
||||
)
|
||||
push!(handle, ax[:add_patch](patches))
|
||||
push!(handle, ax."add_patch"(patches))
|
||||
end
|
||||
end
|
||||
push!(handles, handle)
|
||||
end
|
||||
|
||||
if st == :pie
|
||||
handle = ax[:pie](y;
|
||||
handle = ax."pie"(y;
|
||||
# colors = # a vector of colors?
|
||||
labels = pie_labels(sp, series)
|
||||
)[1]
|
||||
@@ -820,7 +844,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng)
|
||||
end
|
||||
|
||||
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
|
||||
handle = getproperty(ax, f)(args..., trues(n), false, py_fillstepstyle(st);
|
||||
zorder = series[:series_plotindex],
|
||||
facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
|
||||
linewidths = 0
|
||||
@@ -838,36 +862,36 @@ end
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
function py_set_lims(ax, axis::Axis)
|
||||
function py_set_lims(ax, sp::Subplot, axis::Axis)
|
||||
letter = axis[:letter]
|
||||
lfrom, lto = axis_limits(axis)
|
||||
ax[Symbol("set_", letter, "lim")](lfrom, lto)
|
||||
lfrom, lto = axis_limits(sp, letter)
|
||||
getproperty(ax, Symbol("set_", letter, "lim"))(lfrom, lto)
|
||||
end
|
||||
|
||||
function py_set_ticks(ax, ticks, letter)
|
||||
ticks == :auto && return
|
||||
axis = ax[Symbol(letter,"axis")]
|
||||
axis = getproperty(ax, Symbol(letter,"axis"))
|
||||
if ticks == :none || ticks == nothing || ticks == false
|
||||
kw = KW()
|
||||
for dir in (:top,:bottom,:left,:right)
|
||||
kw[dir] = kw[Symbol(:label,dir)] = false
|
||||
end
|
||||
axis[:set_tick_params](;which="both", kw...)
|
||||
axis."set_tick_params"(;which="both", kw...)
|
||||
return
|
||||
end
|
||||
|
||||
ttype = ticksType(ticks)
|
||||
if ttype == :ticks
|
||||
axis[:set_ticks](ticks)
|
||||
axis."set_ticks"(ticks)
|
||||
elseif ttype == :ticks_and_labels
|
||||
axis[:set_ticks](ticks[1])
|
||||
axis[:set_ticklabels](ticks[2])
|
||||
axis."set_ticks"(ticks[1])
|
||||
axis."set_ticklabels"(ticks[2])
|
||||
else
|
||||
error("Invalid input for $(letter)ticks: $ticks")
|
||||
end
|
||||
end
|
||||
|
||||
function py_compute_axis_minval(axis::Axis)
|
||||
function py_compute_axis_minval(sp::Subplot, axis::Axis)
|
||||
# compute the smallest absolute value for the log scale's linear threshold
|
||||
minval = 1.0
|
||||
sps = axis.sps
|
||||
@@ -881,17 +905,17 @@ function py_compute_axis_minval(axis::Axis)
|
||||
end
|
||||
|
||||
# now if the axis limits go to a smaller abs value, use that instead
|
||||
vmin, vmax = axis_limits(axis)
|
||||
vmin, vmax = axis_limits(sp, axis[:letter])
|
||||
minval = NaNMath.min(minval, abs(vmin), abs(vmax))
|
||||
|
||||
minval
|
||||
end
|
||||
|
||||
function py_set_scale(ax, axis::Axis)
|
||||
function py_set_scale(ax, sp::Subplot, axis::Axis)
|
||||
scale = axis[:scale]
|
||||
letter = axis[:letter]
|
||||
scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale")
|
||||
func = ax[Symbol("set_", letter, "scale")]
|
||||
func = getproperty(ax, Symbol("set_", letter, "scale"))
|
||||
kw = KW()
|
||||
arg = if scale == :identity
|
||||
"linear"
|
||||
@@ -903,7 +927,7 @@ function py_set_scale(ax, axis::Axis)
|
||||
elseif scale == :log10
|
||||
10
|
||||
end
|
||||
kw[Symbol(:linthresh,letter)] = NaNMath.min(1e-16, py_compute_axis_minval(axis))
|
||||
kw[Symbol(:linthresh,letter)] = NaNMath.min(1e-16, py_compute_axis_minval(sp, axis))
|
||||
"symlog"
|
||||
end
|
||||
func(arg; kw...)
|
||||
@@ -911,16 +935,16 @@ end
|
||||
|
||||
|
||||
function py_set_axis_colors(sp, ax, a::Axis)
|
||||
for (loc, spine) in ax[:spines]
|
||||
spine[:set_color](py_color(a[:foreground_color_border]))
|
||||
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)
|
||||
if PyCall.hasproperty(ax, axissym)
|
||||
tickcolor = sp[:framestyle] in (:zerolines, :grid) ? 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",
|
||||
ax."tick_params"(axis=string(a[:letter]), which="both",
|
||||
colors=tickcolor,
|
||||
labelcolor=py_color(a[:tickfontcolor]))
|
||||
ax[axissym][:label][:set_color](py_color(a[:guidefontcolor]))
|
||||
getproperty(ax, axissym).label.set_color(py_color(a[:guidefontcolor]))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -932,14 +956,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
# update the fig
|
||||
w, h = plt[:size]
|
||||
fig = plt.o
|
||||
fig[:clear]()
|
||||
fig."clear"()
|
||||
dpi = plt[:dpi]
|
||||
fig[:set_size_inches](w/DPI, h/DPI, forward = true)
|
||||
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
|
||||
fig[:set_dpi](plt[:dpi])
|
||||
fig."set_size_inches"(w/DPI, h/DPI, forward = true)
|
||||
getproperty(fig, set_facecolor_sym)(py_color(plt[:background_color_outside]))
|
||||
fig."set_dpi"(plt[:dpi])
|
||||
|
||||
# resize the window
|
||||
PyPlot.plt[:get_current_fig_manager]()[:resize](w, h)
|
||||
PyPlot.plt."get_current_fig_manager"().resize(w, h)
|
||||
|
||||
# initialize subplots
|
||||
for sp in plt.subplots
|
||||
@@ -973,10 +997,10 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
else
|
||||
:title
|
||||
end
|
||||
ax[func][:set_text](sp[:title])
|
||||
ax[func][:set_fontsize](py_thickness_scale(plt, sp[:titlefontsize]))
|
||||
ax[func][:set_family](sp[:titlefontfamily])
|
||||
ax[func][:set_color](py_color(sp[:titlefontcolor]))
|
||||
getproperty(ax, func)."set_text"(sp[:title])
|
||||
getproperty(ax, func)."set_fontsize"(py_thickness_scale(plt, sp[:titlefontsize]))
|
||||
getproperty(ax, func)."set_family"(sp[:titlefontfamily])
|
||||
getproperty(ax, func)."set_color"(py_color(sp[:titlefontcolor]))
|
||||
# ax[:set_title](sp[:title], loc = loc)
|
||||
end
|
||||
|
||||
@@ -996,7 +1020,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
|
||||
elseif any(colorbar_series[attr] != nothing for attr in (:line_z, :fill_z, :marker_z))
|
||||
cmin, cmax = get_clims(sp)
|
||||
norm = pycolors[:Normalize](vmin = cmin, vmax = cmax)
|
||||
norm = pycolors."Normalize"(vmin = cmin, vmax = cmax)
|
||||
f = if colorbar_series[:line_z] != nothing
|
||||
py_linecolormap
|
||||
elseif colorbar_series[:fill_z] != nothing
|
||||
@@ -1004,21 +1028,22 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
else
|
||||
py_markercolormap
|
||||
end
|
||||
cmap = pycmap[:ScalarMappable](norm = norm, cmap = f(colorbar_series))
|
||||
cmap[:set_array]([])
|
||||
cmap = pycmap."ScalarMappable"(norm = norm, cmap = f(colorbar_series))
|
||||
cmap."set_array"([])
|
||||
handle = cmap
|
||||
end
|
||||
kw[:spacing] = "proportional"
|
||||
|
||||
# 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],size=py_thickness_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor]))
|
||||
for lab in cb[:ax][:yaxis][:get_ticklabels]()
|
||||
lab[:set_fontsize](py_thickness_scale(plt, sp[:yaxis][:tickfontsize]))
|
||||
lab[:set_family](sp[:yaxis][:tickfontfamily])
|
||||
lab[:set_color](py_color(sp[:yaxis][:tickfontcolor]))
|
||||
cbax = fig."add_axes"([0.8,0.1,0.03,0.8], label = string(gensym()))
|
||||
cb = fig."colorbar"(handle; cax = cbax, kw...)
|
||||
cb."set_label"(sp[:colorbar_title],size=py_thickness_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor]))
|
||||
for lab in cb."ax"."yaxis"."get_ticklabels"()
|
||||
lab."set_fontsize"(py_thickness_scale(plt, sp[:yaxis][:tickfontsize]))
|
||||
lab."set_family"(sp[:yaxis][:tickfontfamily])
|
||||
lab."set_color"(py_color(sp[:yaxis][:tickfontcolor]))
|
||||
end
|
||||
sp.attr[:cbar_handle] = cb
|
||||
sp.attr[:cbar_ax] = cbax
|
||||
@@ -1026,28 +1051,28 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
|
||||
# framestyle
|
||||
if !ispolar(sp) && !is3d(sp)
|
||||
ax[:spines]["left"][:set_linewidth](py_thickness_scale(plt, 1))
|
||||
ax[:spines]["bottom"][:set_linewidth](py_thickness_scale(plt, 1))
|
||||
ax.spines["left"]."set_linewidth"(py_thickness_scale(plt, 1))
|
||||
ax.spines["bottom"]."set_linewidth"(py_thickness_scale(plt, 1))
|
||||
if sp[:framestyle] == :semi
|
||||
intensity = 0.5
|
||||
ax[:spines]["right"][:set_alpha](intensity)
|
||||
ax[:spines]["top"][:set_alpha](intensity)
|
||||
ax[:spines]["right"][:set_linewidth](py_thickness_scale(plt, intensity))
|
||||
ax[:spines]["top"][:set_linewidth](py_thickness_scale(plt, intensity))
|
||||
ax.spines["right"]."set_alpha"(intensity)
|
||||
ax.spines["top"]."set_alpha"(intensity)
|
||||
ax.spines["right"]."set_linewidth"(py_thickness_scale(plt, intensity))
|
||||
ax.spines["top"]."set_linewidth"(py_thickness_scale(plt, intensity))
|
||||
elseif sp[:framestyle] in (:axes, :origin)
|
||||
ax[:spines]["right"][:set_visible](false)
|
||||
ax[:spines]["top"][:set_visible](false)
|
||||
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")
|
||||
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)
|
||||
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 = py_thickness_scale(plt, 0.75))
|
||||
ax[:axvline](x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
|
||||
ax."axhline"(y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
|
||||
ax."axvline"(x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1055,51 +1080,51 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
# axis attributes
|
||||
for letter in (:x, :y, :z)
|
||||
axissym = Symbol(letter, :axis)
|
||||
haskey(ax, axissym) || continue
|
||||
PyCall.hasproperty(ax, axissym) || continue
|
||||
axis = sp[axissym]
|
||||
pyaxis = ax[axissym]
|
||||
pyaxis = getproperty(ax, axissym)
|
||||
if axis[:mirror] && letter != :z
|
||||
pos = letter == :x ? "top" : "right"
|
||||
pyaxis[:set_label_position](pos) # the guides
|
||||
pyaxis[:set_ticks_position]("both") # the hash marks
|
||||
pyaxis[Symbol(:tick_, pos)]() # the tick labels
|
||||
pyaxis."set_label_position"(pos) # the guides
|
||||
pyaxis."set_ticks_position"("both") # the hash marks
|
||||
getproperty(pyaxis, Symbol(:tick_, pos))() # the tick labels
|
||||
end
|
||||
if axis[:guide_position] != :auto && letter != :z
|
||||
pyaxis[:set_label_position](axis[:guide_position])
|
||||
pyaxis."set_label_position"(axis[:guide_position])
|
||||
end
|
||||
py_set_scale(ax, axis)
|
||||
axis[:ticks] != :native ? py_set_lims(ax, axis) : nothing
|
||||
py_set_scale(ax, sp, axis)
|
||||
axis[:ticks] != :native ? py_set_lims(ax, sp, axis) : nothing
|
||||
if ispolar(sp) && letter == :y
|
||||
ax[:set_rlabel_position](90)
|
||||
ax."set_rlabel_position"(90)
|
||||
end
|
||||
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
|
||||
ticks = sp[:framestyle] == :none ? nothing : get_ticks(sp, 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
|
||||
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
|
||||
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
|
||||
ax[Symbol("set_", letter, "label")](axis[:guide])
|
||||
pyaxis."set_tick_params"(direction = axis[:tick_direction] == :out ? "out" : "in")
|
||||
getproperty(ax, Symbol("set_", letter, "label"))(axis[:guide])
|
||||
if get(axis.plotattributes, :flip, false)
|
||||
ax[Symbol("invert_", letter, "axis")]()
|
||||
getproperty(ax, Symbol("invert_", letter, "axis"))()
|
||||
end
|
||||
pyaxis[:label][:set_fontsize](py_thickness_scale(plt, axis[:guidefontsize]))
|
||||
pyaxis[:label][:set_family](axis[:guidefontfamily])
|
||||
for lab in ax[Symbol("get_", letter, "ticklabels")]()
|
||||
lab[:set_fontsize](py_thickness_scale(plt, axis[:tickfontsize]))
|
||||
lab[:set_family](axis[:tickfontfamily])
|
||||
lab[:set_rotation](axis[:rotation])
|
||||
pyaxis."label"."set_fontsize"(py_thickness_scale(plt, axis[:guidefontsize]))
|
||||
pyaxis."label"."set_family"(axis[:guidefontfamily])
|
||||
for lab in getproperty(ax, Symbol("get_", letter, "ticklabels"))()
|
||||
lab."set_fontsize"(py_thickness_scale(plt, axis[:tickfontsize]))
|
||||
lab."set_family"(axis[:tickfontfamily])
|
||||
lab."set_rotation"(axis[:rotation])
|
||||
end
|
||||
if axis[:grid] && !(ticks in (:none, nothing, false))
|
||||
fgcolor = py_color(axis[:foreground_color_grid])
|
||||
pyaxis[:grid](true,
|
||||
pyaxis."grid"(true,
|
||||
color = fgcolor,
|
||||
linestyle = py_linestyle(:line, axis[:gridstyle]),
|
||||
linewidth = py_thickness_scale(plt, axis[:gridlinewidth]),
|
||||
alpha = axis[:gridalpha])
|
||||
ax[:set_axisbelow](true)
|
||||
ax."set_axisbelow"(true)
|
||||
else
|
||||
pyaxis[:grid](false)
|
||||
pyaxis."grid"(false)
|
||||
end
|
||||
py_set_axis_colors(sp, ax, axis)
|
||||
end
|
||||
@@ -1107,50 +1132,51 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
# showaxis
|
||||
if !sp[:xaxis][:showaxis]
|
||||
kw = KW()
|
||||
if ispolar(sp)
|
||||
ax.spines["polar"].set_visible(false)
|
||||
end
|
||||
for dir in (:top, :bottom)
|
||||
if ispolar(sp)
|
||||
ax[:spines]["polar"][:set_visible](false)
|
||||
else
|
||||
ax[:spines][string(dir)][:set_visible](false)
|
||||
if !ispolar(sp)
|
||||
ax.spines[string(dir)].set_visible(false)
|
||||
end
|
||||
kw[dir] = kw[Symbol(:label,dir)] = false
|
||||
end
|
||||
ax[:xaxis][:set_tick_params](; which="both", kw...)
|
||||
ax."xaxis"."set_tick_params"(; which="both", kw...)
|
||||
end
|
||||
if !sp[:yaxis][:showaxis]
|
||||
kw = KW()
|
||||
for dir in (:left, :right)
|
||||
if !ispolar(sp)
|
||||
ax[:spines][string(dir)][:set_visible](false)
|
||||
ax.spines[string(dir)].set_visible(false)
|
||||
end
|
||||
kw[dir] = kw[Symbol(:label,dir)] = false
|
||||
end
|
||||
ax[:yaxis][:set_tick_params](; which="both", kw...)
|
||||
ax."yaxis"."set_tick_params"(; which="both", kw...)
|
||||
end
|
||||
|
||||
# aspect ratio
|
||||
aratio = sp[:aspect_ratio]
|
||||
if aratio != :none
|
||||
ax[:set_aspect](isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C")
|
||||
ax."set_aspect"(isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C")
|
||||
end
|
||||
|
||||
#camera/view angle
|
||||
if is3d(sp)
|
||||
#convert azimuthal to match GR behaviour
|
||||
#view_init(elevation, azimuthal) so reverse :camera args
|
||||
ax[:view_init]((sp[:camera].-(90,0))[end:-1:1]...)
|
||||
ax."view_init"((sp[:camera].-(90,0))[end:-1:1]...)
|
||||
end
|
||||
|
||||
# legend
|
||||
py_add_legend(plt, sp, ax)
|
||||
|
||||
# this sets the bg color inside the grid
|
||||
ax[set_facecolor_sym](py_color(sp[:background_color_inside]))
|
||||
getproperty(ax, set_facecolor_sym)(py_color(sp[:background_color_inside]))
|
||||
|
||||
# link axes
|
||||
x_ax_link, y_ax_link = sp[:xaxis].sps[1].o, sp[:yaxis].sps[1].o
|
||||
ax != x_ax_link && ax[:get_shared_x_axes]()[:join](ax, sp[:xaxis].sps[1].o)
|
||||
ax != y_ax_link && ax[:get_shared_y_axes]()[:join](ax, sp[:yaxis].sps[1].o)
|
||||
ax != x_ax_link && ax."get_shared_x_axes"()."join"(ax, sp[:xaxis].sps[1].o)
|
||||
ax != y_ax_link && ax."get_shared_y_axes"()."join"(ax, sp[:yaxis].sps[1].o)
|
||||
end
|
||||
py_drawfig(fig)
|
||||
end
|
||||
@@ -1170,7 +1196,7 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
|
||||
toppad = 0mm
|
||||
rightpad = 0mm
|
||||
bottompad = 0mm
|
||||
for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax))
|
||||
for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax), py_bbox_legend(ax))
|
||||
if ispositive(width(bb)) && ispositive(height(bb))
|
||||
leftpad = max(leftpad, left(plotbb) - left(bb))
|
||||
toppad = max(toppad, top(plotbb) - top(bb))
|
||||
@@ -1181,7 +1207,7 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
|
||||
|
||||
# optionally add the width of colorbar labels and colorbar to rightpad
|
||||
if haskey(sp.attr, :cbar_ax)
|
||||
bb = py_bbox(sp.attr[:cbar_handle][:ax][:get_yticklabels]())
|
||||
bb = py_bbox(sp.attr[:cbar_handle]."ax"."get_yticklabels"())
|
||||
sp.attr[:cbar_width] = _cbar_width + width(bb) + 2.3mm + (sp[:colorbar_title] == "" ? 0px : 30px)
|
||||
rightpad = rightpad + sp.attr[:cbar_width]
|
||||
end
|
||||
@@ -1202,13 +1228,13 @@ end
|
||||
|
||||
function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val)
|
||||
ax = sp.o
|
||||
ax[:annotate](val, xy = (x,y), zorder = 999)
|
||||
ax."annotate"(val, xy = (x,y), zorder = 999)
|
||||
end
|
||||
|
||||
|
||||
function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText)
|
||||
ax = sp.o
|
||||
ax[:annotate](val.str,
|
||||
ax."annotate"(val.str,
|
||||
xy = (x,y),
|
||||
family = val.font.family,
|
||||
color = py_color(val.font.color),
|
||||
@@ -1233,6 +1259,34 @@ const _pyplot_legend_pos = KW(
|
||||
:topleft => "upper left"
|
||||
)
|
||||
|
||||
const _pyplot_legend_pos_outer = KW(
|
||||
:outerright => "center left",
|
||||
:outerleft => "right",
|
||||
:outertop => "lower center",
|
||||
:outerbottom => "upper center",
|
||||
:outerbottomleft => "lower right",
|
||||
:outerbottomright => "lower left",
|
||||
:outertopright => "upper left",
|
||||
:outertopleft => "upper right"
|
||||
)
|
||||
|
||||
py_legend_pos(pos::Symbol) = get(_pyplot_legend_pos, pos, get(_pyplot_legend_pos_outer, pos, "best"))
|
||||
py_legend_pos(pos) = "lower left"
|
||||
|
||||
const _pyplot_legend_bbox_outer = KW(
|
||||
:outerright => (1.0, 0.5, 0.0, 0.0),
|
||||
:outerleft => (-0.15, 0.5, 0.0, 0.0),
|
||||
:outertop => (0.5, 1.0, 0.0, 0.0),
|
||||
:outerbottom => (0.5, -0.15, 0.0, 0.0),
|
||||
:outerbottomleft => (-0.15, 0.0, 0.0, 0.0),
|
||||
:outerbottomright => (1.0, 0.0, 0.0, 0.0),
|
||||
:outertopright => (1.0, 1.0, 0.0, 0.0),
|
||||
:outertopleft => (-0.15, 1.0, 0.0, 0.0)
|
||||
)
|
||||
|
||||
py_legend_bbox(pos::Symbol) = get(_pyplot_legend_bbox_outer, pos, (0.0, 0.0, 1.0, 1.0))
|
||||
py_legend_bbox(pos) = pos
|
||||
|
||||
function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
leg = sp[:legend]
|
||||
clims = get_clims(sp)
|
||||
@@ -1244,20 +1298,20 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
if should_add_to_legend(series)
|
||||
# add a line/marker and a label
|
||||
push!(handles, if series[:seriestype] == :shape || series[:fillrange] != nothing
|
||||
pypatches[:Patch](
|
||||
edgecolor = py_color(get_linecolor(series, clims), get_linealpha(series)),
|
||||
facecolor = py_color(get_fillcolor(series, clims), get_fillalpha(series)),
|
||||
pypatches."Patch"(
|
||||
edgecolor = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)),
|
||||
facecolor = py_color(single_color(get_fillcolor(series, clims)), get_fillalpha(series)),
|
||||
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
linestyle = py_linestyle(series[:seriestype], get_linestyle(series))
|
||||
)
|
||||
elseif series[:seriestype] in (:path, :straightline, :scatter)
|
||||
PyPlot.plt[:Line2D]((0,1),(0,0),
|
||||
color = py_color(get_linecolor(series, clims), get_linealpha(series)),
|
||||
PyPlot.plt."Line2D"((0,1),(0,0),
|
||||
color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)),
|
||||
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
linestyle = py_linestyle(:path, get_linestyle(series)),
|
||||
marker = py_marker(first(series[:markershape])),
|
||||
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
|
||||
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series, clims), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
|
||||
markeredgecolor = py_color(single_color(get_markerstrokecolor(series)), get_markerstrokealpha(series)),
|
||||
markerfacecolor = py_color(single_color(get_markercolor(series, clims)), get_markeralpha(series))
|
||||
)
|
||||
else
|
||||
series[:serieshandle][1]
|
||||
@@ -1268,22 +1322,23 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
|
||||
# if anything was added, call ax.legend and set the colors
|
||||
if !isempty(handles)
|
||||
leg = ax[:legend](handles,
|
||||
leg = ax."legend"(handles,
|
||||
labels,
|
||||
loc = get(_pyplot_legend_pos, leg, "best"),
|
||||
loc = py_legend_pos(leg),
|
||||
bbox_to_anchor = py_legend_bbox(leg),
|
||||
scatterpoints = 1,
|
||||
fontsize = py_thickness_scale(plt, sp[:legendfontsize]),
|
||||
facecolor = py_color(sp[:background_color_legend]),
|
||||
edgecolor = py_color(sp[:foreground_color_legend]),
|
||||
framealpha = alpha(plot_color(sp[:background_color_legend])),
|
||||
)
|
||||
frame = leg[:get_frame]()
|
||||
frame[:set_linewidth](py_thickness_scale(plt, 1))
|
||||
leg[:set_zorder](1000)
|
||||
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
|
||||
frame = leg."get_frame"()
|
||||
frame."set_linewidth"(py_thickness_scale(plt, 1))
|
||||
leg."set_zorder"(1000)
|
||||
sp[:legendtitle] != nothing && leg."set_title"(sp[:legendtitle])
|
||||
|
||||
for txt in leg[:get_texts]()
|
||||
PyPlot.plt[:setp](txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily])
|
||||
for txt in leg."get_texts"()
|
||||
PyPlot.plt."setp"(txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1301,7 +1356,7 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
|
||||
figw, figh = sp.plt[:size]
|
||||
figw, figh = figw*px, figh*px
|
||||
pcts = bbox_to_pcts(sp.plotarea, figw, figh)
|
||||
ax[:set_position](pcts)
|
||||
ax."set_position"(pcts)
|
||||
|
||||
# set the cbar position if there is one
|
||||
if haskey(sp.attr, :cbar_ax)
|
||||
@@ -1311,7 +1366,7 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
|
||||
has_toplabel = !(1e-7 < max(abs(ex.emax), abs(ex.emin)) < 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)
|
||||
sp.attr[:cbar_ax]."set_position"(pcts)
|
||||
end
|
||||
end
|
||||
PyPlot.draw()
|
||||
@@ -1320,9 +1375,7 @@ end
|
||||
# -----------------------------------------------------------------
|
||||
# display/output
|
||||
|
||||
function _display(plt::Plot{PyPlotBackend})
|
||||
plt.o[:show]()
|
||||
end
|
||||
_display(plt::Plot{PyPlotBackend}) = plt.o."show"()
|
||||
|
||||
|
||||
|
||||
@@ -1332,23 +1385,24 @@ const _pyplot_mimeformats = Dict(
|
||||
"application/pdf" => "pdf",
|
||||
"image/png" => "png",
|
||||
"application/postscript" => "ps",
|
||||
"image/svg+xml" => "svg"
|
||||
"image/svg+xml" => "svg",
|
||||
"application/x-tex" => "pgf"
|
||||
)
|
||||
|
||||
|
||||
for (mime, fmt) in _pyplot_mimeformats
|
||||
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PyPlotBackend})
|
||||
fig = plt.o
|
||||
fig[:canvas][:print_figure](
|
||||
fig."canvas"."print_figure"(
|
||||
io,
|
||||
format=$fmt,
|
||||
# bbox_inches = "tight",
|
||||
# figsize = map(px2inch, plt[:size]),
|
||||
facecolor = fig[:get_facecolor](),
|
||||
facecolor = fig."get_facecolor"(),
|
||||
edgecolor = "none",
|
||||
dpi = plt[:dpi]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
closeall(::PyPlotBackend) = PyPlot.plt[:close]("all")
|
||||
closeall(::PyPlotBackend) = PyPlot.plt."close"("all")
|
||||
|
||||
@@ -27,8 +27,8 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
for sp in plt.subplots
|
||||
xaxis = sp[:xaxis]
|
||||
yaxis = sp[:yaxis]
|
||||
xlim = axis_limits(xaxis)
|
||||
ylim = axis_limits(yaxis)
|
||||
xlim = axis_limits(sp, :x)
|
||||
ylim = axis_limits(sp, :y)
|
||||
|
||||
# make vectors
|
||||
xlim = [xlim[1], xlim[2]]
|
||||
@@ -116,7 +116,7 @@ function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
|
||||
x, y = if st == :straightline
|
||||
straightline_data(plotattributes)
|
||||
elseif st == :shape
|
||||
shape_data(series)
|
||||
shape_data(plotattributes)
|
||||
else
|
||||
[collect(float(plotattributes[s])) for s in (:x, :y)]
|
||||
end
|
||||
|
||||
+7
-10
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
const P2 = StaticArrays.SVector{2,Float64}
|
||||
const P3 = StaticArrays.SVector{3,Float64}
|
||||
const P2 = GeometryTypes.Point2{Float64}
|
||||
const P3 = GeometryTypes.Point3{Float64}
|
||||
|
||||
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
|
||||
@@ -261,13 +261,13 @@ end
|
||||
Create a Font from a list of features. Values may be specified either as
|
||||
arguments (which are distinguished by type/value) or as keyword arguments.
|
||||
# Arguments
|
||||
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
|
||||
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
|
||||
- `pointsize`: Integer. Size of font in points
|
||||
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
|
||||
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
|
||||
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
|
||||
- `color`: Colorant or Symbol
|
||||
# Examples
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> font(8)
|
||||
julia> font(family="serif",halign=:center,rotation=45.0)
|
||||
@@ -388,8 +388,8 @@ PlotText(str) = PlotText(string(str), font())
|
||||
"""
|
||||
text(string, args...; kw...)
|
||||
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations.
|
||||
`args` and `kw` are passed to `font`.
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations.
|
||||
`args` and `kw` are passed to `font`.
|
||||
"""
|
||||
text(t::PlotText) = t
|
||||
text(t::PlotText, font::Font) = PlotText(t.str, font)
|
||||
@@ -779,7 +779,7 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
"create a BezierCurve for plotting"
|
||||
mutable struct BezierCurve{T <: StaticArrays.SVector}
|
||||
mutable struct BezierCurve{T <: GeometryTypes.Point}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
@@ -792,9 +792,6 @@ function (bc::BezierCurve)(t::Real)
|
||||
p
|
||||
end
|
||||
|
||||
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
|
||||
# mean{N,T<:Real}(ps::StaticArrays.SVector{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
|
||||
|
||||
@deprecate curve_points coords
|
||||
|
||||
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, range(range..., stop=n, length=50))
|
||||
|
||||
+3
-2
@@ -86,8 +86,9 @@ yaxis!("YLABEL", :log10)
|
||||
PlotExample("Images",
|
||||
"Plot an image. y-axis is set to flipped",
|
||||
[:(begin
|
||||
import FileIO, PlotReferenceImages
|
||||
img = FileIO.load(joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots","pyplot","0.7.0","ref1.png"))
|
||||
import FileIO
|
||||
path = download("http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png")
|
||||
img = FileIO.load(path)
|
||||
plot(img)
|
||||
end)]
|
||||
),
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ using REPL
|
||||
|
||||
function _plots_defaults()
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
Main.PLOTS_DEFAULTS::Dict{Symbol,Any}
|
||||
Dict{Symbol,Any}(Main.PLOTS_DEFAULTS)
|
||||
else
|
||||
Dict{Symbol,Any}()
|
||||
end
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
|
||||
pct += mix.len / totlen
|
||||
end
|
||||
if pct != 0
|
||||
amin, amax = axis_limits(sp[Symbol(letter,:axis)])
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
xy += pct * (amax-amin)
|
||||
end
|
||||
xy
|
||||
|
||||
+3
-4
@@ -55,9 +55,7 @@ tex(fn::AbstractString) = tex(current(), fn)
|
||||
function html(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "html")
|
||||
io = open(fn, "w")
|
||||
_use_remote[] = true
|
||||
show(io, MIME("text/html"), plt)
|
||||
_use_remote[] = false
|
||||
close(io)
|
||||
end
|
||||
html(fn::AbstractString) = html(current(), fn)
|
||||
@@ -105,7 +103,7 @@ 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)
|
||||
|
||||
fn = abspath(expanduser(fn))
|
||||
# get the extension
|
||||
local ext
|
||||
try
|
||||
@@ -191,7 +189,7 @@ end
|
||||
# for writing to io streams... first prepare, then callback
|
||||
for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml",
|
||||
"application/eps", "application/pdf", "application/postscript",
|
||||
"application/x-tex")
|
||||
"application/x-tex", "application/vnd.plotly.v1+json")
|
||||
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
|
||||
if haskey(io, :juno_plotsize)
|
||||
showjuno(io, m, plt)
|
||||
@@ -199,6 +197,7 @@ for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml
|
||||
prepare_output(plt)
|
||||
_show(io, m, plt)
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+7
-2
@@ -50,8 +50,13 @@ function plotattr(attrtype::Symbol, attribute::AbstractString)
|
||||
|
||||
desc = get(_arg_desc, attribute, "")
|
||||
first_period_idx = findfirst(isequal('.'), desc)
|
||||
typedesc = desc[1:first_period_idx-1]
|
||||
desc = strip(desc[first_period_idx+1:end])
|
||||
if isnothing(first_period_idx)
|
||||
typedesc = ""
|
||||
desc = strip(desc)
|
||||
else
|
||||
typedesc = desc[1:first_period_idx-1]
|
||||
desc = strip(desc[first_period_idx+1:end])
|
||||
end
|
||||
als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort
|
||||
als = join(map(string,als), ", ")
|
||||
def = _attribute_defaults[attrtype][attribute]
|
||||
|
||||
+69
-22
@@ -47,16 +47,47 @@ end
|
||||
num_series(x::AMat) = size(x,2)
|
||||
num_series(x) = 1
|
||||
|
||||
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
|
||||
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
# for seriestype `line`, need to sort by x values
|
||||
|
||||
const POTENTIAL_VECTOR_ARGUMENTS = [
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linealpha, :linewidth, :linestyle, :line_z,
|
||||
:fillcolor, :fillalpha, :fill_z,
|
||||
:markercolor, :markeralpha, :markershape, :marker_z,
|
||||
:markerstrokecolor, :markerstrokealpha,
|
||||
:yerror, :yerror,
|
||||
:series_annotations, :fillrange
|
||||
]
|
||||
|
||||
@recipe function f(::Type{Val{:line}}, x, y, z)
|
||||
indices = sortperm(x)
|
||||
x := x[indices]
|
||||
y := y[indices]
|
||||
|
||||
# sort vector arguments
|
||||
for arg in POTENTIAL_VECTOR_ARGUMENTS
|
||||
if typeof(plotattributes[arg]) <: AVec
|
||||
plotattributes[arg] = _cycle(plotattributes[arg], indices)
|
||||
end
|
||||
end
|
||||
|
||||
# a tuple as fillrange has to be handled differently
|
||||
if typeof(plotattributes[:fillrange]) <: Tuple
|
||||
lower, upper = plotattributes[:fillrange]
|
||||
if typeof(lower) <: AVec
|
||||
lower = _cycle(lower, indices)
|
||||
end
|
||||
if typeof(upper) <: AVec
|
||||
upper = _cycle(upper, indices)
|
||||
end
|
||||
plotattributes[:fillrange] = (lower, upper)
|
||||
end
|
||||
|
||||
if typeof(z) <: AVec
|
||||
z := z[indices]
|
||||
end
|
||||
@@ -65,19 +96,6 @@ RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where
|
||||
end
|
||||
@deps line path
|
||||
|
||||
|
||||
function hvline_limits(axis::Axis)
|
||||
vmin, vmax = axis_limits(axis)
|
||||
if vmin >= vmax
|
||||
if isfinite(vmin)
|
||||
vmax = vmin + 1
|
||||
else
|
||||
vmin, vmax = 0.0, 1.1
|
||||
end
|
||||
end
|
||||
vmin, vmax
|
||||
end
|
||||
|
||||
@recipe function f(::Type{Val{:hline}}, x, y, z)
|
||||
n = length(y)
|
||||
newx = repeat(Float64[-1, 1, NaN], n)
|
||||
@@ -222,11 +240,12 @@ end
|
||||
n = length(x)
|
||||
fr = plotattributes[:fillrange]
|
||||
if fr == nothing
|
||||
yaxis = plotattributes[:subplot][:yaxis]
|
||||
sp = plotattributes[:subplot]
|
||||
yaxis = sp[:yaxis]
|
||||
fr = if yaxis[:scale] == :identity
|
||||
0.0
|
||||
else
|
||||
NaNMath.min(axis_limits(yaxis)[1], ignorenan_minimum(y))
|
||||
NaNMath.min(axis_limits(sp, :y)[1], ignorenan_minimum(y))
|
||||
end
|
||||
end
|
||||
newx, newy = zeros(3n), zeros(3n)
|
||||
@@ -519,13 +538,15 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
|
||||
w, it_state_w = it_tuple_w
|
||||
|
||||
if (log_scale_x && a ≈ 0)
|
||||
a = b/_logScaleBases[xscale]^3
|
||||
a = oftype(a, b/_logScaleBases[xscale]^3)
|
||||
end
|
||||
|
||||
if isnan(w)
|
||||
if !isnan(last_w)
|
||||
push!(x, a)
|
||||
push!(y, baseline)
|
||||
push!(x, NaN)
|
||||
push!(y, NaN)
|
||||
end
|
||||
else
|
||||
if isnan(last_w)
|
||||
@@ -538,8 +559,8 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
|
||||
push!(y, w)
|
||||
end
|
||||
|
||||
a = b
|
||||
last_w = w
|
||||
a = oftype(a, b)
|
||||
last_w = oftype(last_w, w)
|
||||
|
||||
it_tuple_e = iterate(edge, it_state_e)
|
||||
it_tuple_w = iterate(weights, it_state_w)
|
||||
@@ -589,7 +610,8 @@ Plots.@deps stepbins path
|
||||
wand_edges(x...) = (@warn("Load the StatsPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
||||
|
||||
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
|
||||
_cl(x) = ceil(Int, max(x, one(x)))
|
||||
max_bins = 10_000
|
||||
_cl(x) = min(ceil(Int, max(x, one(x))), max_bins)
|
||||
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
|
||||
_span(v) = maximum(v) - minimum(v)
|
||||
|
||||
@@ -616,7 +638,7 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
|
||||
elseif mode == :fd # Freedman–Diaconis rule
|
||||
_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
|
||||
_cl(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
|
||||
@@ -1061,7 +1083,7 @@ end
|
||||
|
||||
# -------------------------------------------------
|
||||
|
||||
"Adds a+bx... straight line over the current plot, without changing the axis limits"
|
||||
"Adds ax+b... straight line over the current plot, without changing the axis limits"
|
||||
abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...)
|
||||
|
||||
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
@@ -1077,6 +1099,7 @@ timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
|
||||
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
|
||||
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter)
|
||||
@recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter)
|
||||
@recipe f(::Type{P}, t::P) where P <: Dates.Period = (t -> Dates.value(t), t -> string(P(t)))
|
||||
|
||||
# -------------------------------------------------
|
||||
# Complex Numbers
|
||||
@@ -1161,3 +1184,27 @@ end
|
||||
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
areaplot([x,] y)
|
||||
areaplot!([x,] y)
|
||||
|
||||
Draw a stacked area plot of the matrix y.
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], fillalpha = [0.2 0.3 0.4])
|
||||
```
|
||||
"""
|
||||
@userplot AreaPlot
|
||||
|
||||
@recipe function f(a::AreaPlot)
|
||||
data = cumsum(a.args[end], dims=2)
|
||||
x = length(a.args) == 1 ? (1:size(data, 1)) : a.args[1]
|
||||
seriestype := :line
|
||||
for i in 1:size(data, 2)
|
||||
@series begin
|
||||
fillrange := i > 1 ? data[:,i-1] : 0
|
||||
x, data[:,i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+47
-98
@@ -7,72 +7,36 @@
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
|
||||
const DataPoint = Union{Number, AbstractString, AbstractChar, Missing}
|
||||
const SeriesData = Union{AVec{<:DataPoint}, Function, Surface, Volume}
|
||||
|
||||
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none))
|
||||
prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting")
|
||||
prepareSeriesData(::Nothing) = nothing
|
||||
prepareSeriesData(s::SeriesData) = handlemissings(handlechars(s))
|
||||
|
||||
# unknown
|
||||
convertToAnyVector(x, plotattributes::KW) = error("No user recipe defined for $(typeof(x))")
|
||||
handlemissings(v) = v
|
||||
handlemissings(v::AbstractArray{Union{T,Missing}}) where T <: Number = replace(v, missing => NaN)
|
||||
handlemissings(v::AbstractArray{Union{T,Missing}}) where T <: AbstractString = replace(v, missing => "")
|
||||
handlemissings(s::Surface) = Surface(handlemissings(s.surf))
|
||||
handlemissings(v::Volume) = Volume(handlemissings(v.v), v.x_extents, v.y_extents, v.z_extents)
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
|
||||
handlechars(x) = x
|
||||
handlechars(c::AVec{<:AbstractChar}) = string.(c)
|
||||
|
||||
# default: assume x represents a single series
|
||||
convertToAnyVector(x) = Any[prepareSeriesData(x)]
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
convertToAnyVector(n::Integer) = Any[zeros(0) for i in 1:n]
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{Union{Missing, T}}, plotattributes::KW) where {T<:Number} = Any[replace(v, missing => NaN)], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{Union{Missing, T}}, plotattributes::KW) where {T<:AbstractString} = Any[replace(v, missing => "")], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, plotattributes::KW)
|
||||
v = handlemissings(v)
|
||||
if all3D(plotattributes)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
handlemissings(v::AMat) = v
|
||||
handlemissings(v::AMat{T}) where T <: Number = replace(v, missing => NaN)
|
||||
handlemissings(v::AMat{T}) where T <: String = replace(v, missing => "")
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
|
||||
|
||||
# volume
|
||||
convertToAnyVector(v::Volume, plotattributes::KW) = Any[v], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
|
||||
|
||||
# # dates
|
||||
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
# vector of data points is a single series
|
||||
convertToAnyVector(v::AVec{<:DataPoint}) = Any[prepareSeriesData(v)]
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, plotattributes::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
convertToAnyVector(v::AVec) = vcat((convertToAnyVector(vi) for vi in v)...)
|
||||
|
||||
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
|
||||
|
||||
|
||||
function convertToAnyVector(args...)
|
||||
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
|
||||
end
|
||||
# Matrix is split into columns
|
||||
convertToAnyVector(v::AMat{<:DataPoint}) = Any[prepareSeriesData(v[:,i]) for i in 1:size(v,2)]
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@@ -135,23 +99,24 @@ struct SliceIt end
|
||||
z = z.data
|
||||
end
|
||||
|
||||
xs, _ = convertToAnyVector(x, plotattributes)
|
||||
ys, _ = convertToAnyVector(y, plotattributes)
|
||||
zs, _ = convertToAnyVector(z, plotattributes)
|
||||
xs = convertToAnyVector(x)
|
||||
ys = convertToAnyVector(y)
|
||||
zs = convertToAnyVector(z)
|
||||
|
||||
|
||||
fr = pop!(plotattributes, :fillrange, nothing)
|
||||
fillranges, _ = if typeof(fr) <: Number
|
||||
([fr],nothing)
|
||||
fillranges = if typeof(fr) <: Number
|
||||
[fr]
|
||||
else
|
||||
convertToAnyVector(fr, plotattributes)
|
||||
convertToAnyVector(fr)
|
||||
end
|
||||
mf = length(fillranges)
|
||||
|
||||
rib = pop!(plotattributes, :ribbon, nothing)
|
||||
ribbons, _ = if typeof(rib) <: Number
|
||||
([fr],nothing)
|
||||
ribbons = if typeof(rib) <: Number
|
||||
[rib]
|
||||
else
|
||||
convertToAnyVector(rib, plotattributes)
|
||||
convertToAnyVector(rib)
|
||||
end
|
||||
mr = length(ribbons)
|
||||
|
||||
@@ -193,8 +158,9 @@ _apply_type_recipe(plotattributes, v) = RecipesBase.apply_recipe(plotattributes,
|
||||
# This sort of recipe should return a pair of functions... one to convert to number,
|
||||
# and one to format tick values.
|
||||
function _apply_type_recipe(plotattributes, v::AbstractArray)
|
||||
isempty(v) && return Float64[]
|
||||
args = RecipesBase.apply_recipe(plotattributes, typeof(v[1]), v[1])[1].args
|
||||
isempty(skipmissing(v)) && return Float64[]
|
||||
x = first(skipmissing(v))
|
||||
args = RecipesBase.apply_recipe(plotattributes, typeof(x), x)[1].args
|
||||
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
|
||||
numfunc, formatter = args
|
||||
Formatted(map(numfunc, v), formatter)
|
||||
@@ -292,8 +258,10 @@ end
|
||||
|
||||
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
|
||||
|
||||
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none))
|
||||
|
||||
# return a surface if this is a 3d plot, otherwise let it be sliced up
|
||||
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat}
|
||||
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat,Missing}
|
||||
if all3D(plotattributes)
|
||||
n,m = size(mat)
|
||||
wrap_surfaces(plotattributes)
|
||||
@@ -316,7 +284,7 @@ end
|
||||
end
|
||||
|
||||
# assume this is a Volume, so construct one
|
||||
@recipe function f(vol::AbstractArray{T,3}, args...) where T<:Number
|
||||
@recipe function f(vol::AbstractArray{T,3}, args...) where T<:Union{Number,Missing}
|
||||
seriestype := :volume
|
||||
SliceIt, nothing, Volume(vol, args...), nothing
|
||||
end
|
||||
@@ -391,7 +359,7 @@ end
|
||||
@recipe function f(f::FuncOrFuncs{F}) where F<:Function
|
||||
plt = plotattributes[:plot_object]
|
||||
xmin, xmax = try
|
||||
axis_limits(plt[1][:xaxis])
|
||||
axis_limits(plt[1], :x)
|
||||
catch
|
||||
xinv = invscalefunc(get(plotattributes, :xscale, :identity))
|
||||
xm = tryrange(f, xinv.([-5,-1,0,0.01]))
|
||||
@@ -554,36 +522,17 @@ end
|
||||
#
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # Lists of tuples and StaticArrays
|
||||
# # Lists of tuples and GeometryTypes.Points
|
||||
# # --------------------------------------------------------------------
|
||||
#
|
||||
# # if we get an unhandled tuple, just splat it in
|
||||
@recipe f(tup::Tuple) = tup
|
||||
|
||||
#
|
||||
# # (x,y) tuples
|
||||
@recipe f(xy::AVec{Tuple{R1,R2}}) where {R1<:Number,R2<:Number} = unzip(xy)
|
||||
@recipe f(xy::Tuple{R1,R2}) where {R1<:Number,R2<:Number} = [xy[1]], [xy[2]]
|
||||
@recipe f(v::AVec{<:Tuple}) = unzip(v)
|
||||
@recipe f(v::AVec{<:GeometryTypes.Point}) = unzip(v)
|
||||
@recipe f(tup::Tuple) = [tup]
|
||||
@recipe f(p::GeometryTypes.Point) = [p]
|
||||
|
||||
#
|
||||
# # (x,y,z) tuples
|
||||
@recipe f(xyz::AVec{Tuple{R1,R2,R3}}) where {R1<:Number,R2<:Number,R3<:Number} = unzip(xyz)
|
||||
@recipe f(xyz::Tuple{R1,R2,R3}) where {R1<:Number,R2<:Number,R3<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
|
||||
# these might be points+velocity, or OHLC or something else
|
||||
@recipe f(xyuv::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
|
||||
@recipe f(xyuv::Tuple{R1,R2,R3,R4}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
|
||||
|
||||
|
||||
#
|
||||
# # 2D StaticArrays
|
||||
@recipe f(xy::AVec{StaticArrays.SVector{2,T}}) where {T<:Number} = unzip(xy)
|
||||
@recipe f(xy::StaticArrays.SVector{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
|
||||
|
||||
#
|
||||
# # 3D StaticArrays
|
||||
@recipe f(xyz::AVec{StaticArrays.SVector{3,T}}) where {T<:Number} = unzip(xyz)
|
||||
@recipe f(xyz::StaticArrays.SVector{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
# Special case for 4-tuples in :ohlc series
|
||||
@recipe f(xyuv::AVec{<:Tuple{R1,R2,R3,R4}}) where {R1,R2,R3,R4} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
|
||||
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
@@ -604,7 +553,7 @@ end
|
||||
# end
|
||||
|
||||
splittable_kw(key, val, lengthGroup) = false
|
||||
splittable_kw(key, val::AbstractArray, lengthGroup) = (key != :group) && size(val,1) == lengthGroup
|
||||
splittable_kw(key, val::AbstractArray, lengthGroup) = !(key in (:group, :color_palette)) && size(val,1) == lengthGroup
|
||||
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
|
||||
splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup)
|
||||
|
||||
|
||||
+70
-70
@@ -2,10 +2,10 @@
|
||||
scatter(x,y)
|
||||
scatter!(x,y)
|
||||
|
||||
Make a scatter plot of y vs x.
|
||||
Make a scatter plot of y vs x.
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> scatter([1,2,3],[4,5,6],markersize=[3,4,5],markercolor=[:red,:green,:blue])
|
||||
julia> scatter([(1,4),(2,5),(3,6)])
|
||||
```
|
||||
@@ -16,9 +16,9 @@ julia> scatter([(1,4),(2,5),(3,6)])
|
||||
bar(x,y)
|
||||
bar!(x,y)
|
||||
|
||||
Make a bar plot of y vs x.
|
||||
Make a bar plot of y vs x.
|
||||
|
||||
# Arguments
|
||||
# Arguments
|
||||
|
||||
- $(_document_argument("bar_position"))
|
||||
- $(_document_argument("bar_width"))
|
||||
@@ -26,7 +26,7 @@ Make a bar plot of y vs x.
|
||||
- $(_document_argument("orientation"))
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> bar([1,2,3],[4,5,6],fillcolor=[:red,:green,:blue],fillalpha=[0.2,0.4,0.6])
|
||||
julia> bar([(1,4),(2,5),(3,6)])
|
||||
```
|
||||
@@ -41,7 +41,7 @@ julia> bar([(1,4),(2,5),(3,6)])
|
||||
|
||||
Plot a histogram.
|
||||
|
||||
# Arguments
|
||||
# Arguments
|
||||
|
||||
- `x`: AbstractVector of values to be binned
|
||||
- $(_document_argument("bins"))
|
||||
@@ -53,7 +53,7 @@ Plot a histogram.
|
||||
- $(_document_argument("orientation"))
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> histogram([1,2,1,1,4,3,8],bins=0:8)
|
||||
```
|
||||
"""
|
||||
@@ -63,7 +63,7 @@ julia> histogram([1,2,1,1,4,3,8],bins=0:8)
|
||||
barhist(x)
|
||||
barhist!(x)
|
||||
|
||||
Make a histogram bar plot. See `histogram`.
|
||||
Make a histogram bar plot. See `histogram`.
|
||||
"""
|
||||
@shorthands barhist
|
||||
|
||||
@@ -72,7 +72,7 @@ Make a histogram bar plot. See `histogram`.
|
||||
stephist(x)
|
||||
|
||||
Make a histogram step plot (bin counts are represented using horizontal lines
|
||||
instead of bars). See `histogram`.
|
||||
instead of bars). See `histogram`.
|
||||
"""
|
||||
@shorthands stephist
|
||||
|
||||
@@ -80,8 +80,8 @@ instead of bars). See `histogram`.
|
||||
scatterhist(x)
|
||||
scatterhist!(x)
|
||||
|
||||
Make a histogram scatter plot (bin counts are represented using points
|
||||
instead of bars). See `histogram`.
|
||||
Make a histogram scatter plot (bin counts are represented using points
|
||||
instead of bars). See `histogram`.
|
||||
"""
|
||||
@shorthands scatterhist
|
||||
|
||||
@@ -91,14 +91,14 @@ instead of bars). See `histogram`.
|
||||
|
||||
Plot a two-dimensional histogram.
|
||||
|
||||
# Arguments
|
||||
# Arguments
|
||||
|
||||
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
|
||||
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
|
||||
its weight to the height of its bin.
|
||||
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
|
||||
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
|
||||
its weight to the height of its bin.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> histogram2d(randn(10_000),randn(10_000))
|
||||
```
|
||||
"""
|
||||
@@ -108,14 +108,14 @@ julia> histogram2d(randn(10_000),randn(10_000))
|
||||
density(x)
|
||||
density!(x)
|
||||
|
||||
Make a line plot of a kernel density estimate of x.
|
||||
Make a line plot of a kernel density estimate of x.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `x`: AbstractVector of samples for probability density estimation
|
||||
- `x`: AbstractVector of samples for probability density estimation
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> using StatsPlots
|
||||
julia> density(randn(100_000))
|
||||
```
|
||||
@@ -126,10 +126,10 @@ julia> density(randn(100_000))
|
||||
heatmap(x,y,z)
|
||||
heatmap!(x,y,z)
|
||||
|
||||
Plot a heatmap of the rectangular array `z`.
|
||||
Plot a heatmap of the rectangular array `z`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> heatmap(randn(10,10))
|
||||
```
|
||||
"""
|
||||
@@ -140,7 +140,7 @@ julia> heatmap(randn(10,10))
|
||||
hexbin(x,y)
|
||||
hexbin!(x,y)
|
||||
|
||||
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
|
||||
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
|
||||
with hexagonal bins)
|
||||
|
||||
# Example
|
||||
@@ -154,11 +154,11 @@ julia> hexbin(randn(10_000), randn(10_000))
|
||||
sticks(x,y)
|
||||
sticks!(x,y)
|
||||
|
||||
Draw a stick plot of y vs x.
|
||||
Draw a stick plot of y vs x.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> sticks(1:10)
|
||||
julia> sticks(1:10)
|
||||
```
|
||||
"""
|
||||
@shorthands sticks
|
||||
@@ -167,11 +167,11 @@ julia> sticks(1:10)
|
||||
hline(y)
|
||||
hline!(y)
|
||||
|
||||
Draw horizontal lines at positions specified by the values in
|
||||
Draw horizontal lines at positions specified by the values in
|
||||
the AbstractVector `y`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> hline([-1,0,2])
|
||||
```
|
||||
"""
|
||||
@@ -181,11 +181,11 @@ julia> hline([-1,0,2])
|
||||
vline(x)
|
||||
vline!(x)
|
||||
|
||||
Draw vertical lines at positions specified by the values in
|
||||
Draw vertical lines at positions specified by the values in
|
||||
the AbstractVector `x`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> vline([-1,0,2])
|
||||
```
|
||||
"""
|
||||
@@ -194,13 +194,13 @@ julia> vline([-1,0,2])
|
||||
"""
|
||||
hspan(y)
|
||||
|
||||
Draw a rectangle between the horizontal line at position `y[1]`
|
||||
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
|
||||
then further rectangles are drawn between `y[3]` and `y[4]`,
|
||||
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
|
||||
last entry of `y` is ignored.
|
||||
Draw a rectangle between the horizontal line at position `y[1]`
|
||||
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
|
||||
then further rectangles are drawn between `y[3]` and `y[4]`,
|
||||
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
|
||||
last entry of `y` is ignored.
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> hspan(1:6)
|
||||
```
|
||||
"""
|
||||
@@ -209,13 +209,13 @@ julia> hspan(1:6)
|
||||
"""
|
||||
vspan(x)
|
||||
|
||||
Draw a rectangle between the vertical line at position `x[1]`
|
||||
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
|
||||
then further rectangles are drawn between `x[3]` and `x[4]`,
|
||||
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
|
||||
last entry of `x` is ignored.
|
||||
Draw a rectangle between the vertical line at position `x[1]`
|
||||
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
|
||||
then further rectangles are drawn between `x[3]` and `x[4]`,
|
||||
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
|
||||
last entry of `x` is ignored.
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> vspan(1:6)
|
||||
```
|
||||
"""
|
||||
@@ -225,9 +225,9 @@ julia> vspan(1:6)
|
||||
ohlc(x,y::Vector{OHLC})
|
||||
ohlc!(x,y::Vector{OHLC})
|
||||
|
||||
Make open-high-low-close plot. Each entry of y is represented by a vertical
|
||||
segment extending from the low value to the high value, with short horizontal
|
||||
segments on the left and right indicating the open and close values, respectively.
|
||||
Make open-high-low-close plot. Each entry of y is represented by a vertical
|
||||
segment extending from the low value to the high value, with short horizontal
|
||||
segments on the left and right indicating the open and close values, respectively.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
@@ -240,16 +240,16 @@ julia> ohlc(y)
|
||||
|
||||
|
||||
"""
|
||||
contour(x,y,z)
|
||||
contour!(x,y,z)
|
||||
contour(x,y,z)
|
||||
contour!(x,y,z)
|
||||
|
||||
Draw contour lines of the `Surface` z.
|
||||
Draw contour lines of the `Surface` z.
|
||||
|
||||
# Arguments
|
||||
- `levels`: Contour levels (if `AbstractVector`) or number of levels (if `Integer`)
|
||||
- `fill`: Bool. Fill area between contours or draw contours only (false by default)
|
||||
|
||||
# Example
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> x = y = range(-20, 20, length = 100)
|
||||
julia> contour(x, y, (x, y) -> x^2 + y^2)
|
||||
@@ -267,10 +267,10 @@ julia> contour(x, y, (x, y) -> x^2 + y^2)
|
||||
surface(x,y,z)
|
||||
surface!(x,y,z)
|
||||
|
||||
Draw a 3D surface plot.
|
||||
Draw a 3D surface plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> x = y = range(-3, 3, length = 100)
|
||||
julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
|
||||
```
|
||||
@@ -281,10 +281,10 @@ julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
|
||||
wireframe(x,y,z)
|
||||
wireframe!(x,y,z)
|
||||
|
||||
Draw a 3D wireframe plot.
|
||||
Draw a 3D wireframe plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> wireframe(1:10,1:10,randn(10,10))
|
||||
```
|
||||
"""
|
||||
@@ -295,10 +295,10 @@ julia> wireframe(1:10,1:10,randn(10,10))
|
||||
path3d!(x,y,z)
|
||||
|
||||
Plot a 3D path from `(x[1],y[1],z[1])` to `(x[2],y[2],z[2])`,
|
||||
..., to `(x[end],y[end],z[end])`.
|
||||
..., to `(x[end],y[end],z[end])`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
```
|
||||
"""
|
||||
@@ -308,10 +308,10 @@ julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
scatter3d(x,y,z)
|
||||
scatter3d!(x,y,z)
|
||||
|
||||
Make a 3D scatter plot.
|
||||
Make a 3D scatter plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
```
|
||||
"""
|
||||
@@ -321,17 +321,17 @@ julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
boxplot(x, y)
|
||||
boxplot!(x, y)
|
||||
|
||||
Make a box and whisker plot.
|
||||
Make a box and whisker plot.
|
||||
|
||||
# Keyword arguments
|
||||
- `notch`: Bool. Notch the box plot? (false)
|
||||
- `range`: Real. Values more than range*IQR below the first quartile
|
||||
or above the third quartile are shown as outliers (1.5)
|
||||
- `outliers`: Bool. Show outliers? (true)
|
||||
- `whisker_width`: Real or Symbol. Length of whiskers (:match)
|
||||
or above the third quartile are shown as outliers (1.5)
|
||||
- `outliers`: Bool. Show outliers? (true)
|
||||
- `whisker_width`: Real or Symbol. Length of whiskers (:match)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> using StatsPlots
|
||||
julia> boxplot(repeat([1,2,3],outer=100),randn(300))
|
||||
```
|
||||
@@ -342,10 +342,10 @@ julia> boxplot(repeat([1,2,3],outer=100),randn(300))
|
||||
violin(x,y,z)
|
||||
violin!(x,y,z)
|
||||
|
||||
Make a violin plot.
|
||||
Make a violin plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> violin(repeat([1,2,3],outer=100),randn(300))
|
||||
```
|
||||
"""
|
||||
@@ -355,11 +355,11 @@ julia> violin(repeat([1,2,3],outer=100),randn(300))
|
||||
quiver(x,y,quiver=(u,v))
|
||||
quiver!(x,y,quiver=(u,v))
|
||||
|
||||
Make a quiver (vector field) plot. The `i`th vector extends
|
||||
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
|
||||
Make a quiver (vector field) plot. The `i`th vector extends
|
||||
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
|
||||
```
|
||||
"""
|
||||
@@ -369,11 +369,11 @@ julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
|
||||
curves(x,y)
|
||||
curves!(x,y)
|
||||
|
||||
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
|
||||
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
|
||||
with control points `(x[2],y[2]), ..., (x[end-1],y[end]-1)`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
```julia-repl
|
||||
julia> curves([1,2,3,4],[1,1,2,4])
|
||||
```
|
||||
"""
|
||||
@@ -424,9 +424,9 @@ ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} =
|
||||
"""
|
||||
annotate!(anns...)
|
||||
|
||||
Add annotations to an existing plot.
|
||||
Add annotations to an existing plot.
|
||||
|
||||
# Arguments
|
||||
# Arguments
|
||||
|
||||
- `anns`: An `AbstractVector` of tuples of the form (x,y,text). The text object
|
||||
can be an String or PlotText
|
||||
@@ -449,7 +449,7 @@ yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip
|
||||
"Specify x axis attributes for an existing plot"
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
"Specify y 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...)
|
||||
|
||||
+82
-101
@@ -194,7 +194,9 @@ end
|
||||
|
||||
function iter_segments(series::Series)
|
||||
x, y, z = series[:x], series[:y], series[:z]
|
||||
if has_attribute_segments(series)
|
||||
if x == nothing
|
||||
return UnitRange{Int}[]
|
||||
elseif has_attribute_segments(series)
|
||||
if series[:seriestype] in (:scatter, :scatter3d)
|
||||
return [[i] for i in 1:length(y)]
|
||||
else
|
||||
@@ -212,36 +214,19 @@ end
|
||||
|
||||
# helpers to figure out if there are NaN values in a list of array types
|
||||
anynan(i::Int, args::Tuple) = any(a -> try isnan(_cycle(a,i)) catch MethodError false end, 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)
|
||||
anynan(args::Tuple) = i -> anynan(i,args)
|
||||
anynan(istart::Int, iend::Int, args::Tuple) = any(anynan(args), istart:iend)
|
||||
allnan(istart::Int, iend::Int, args::Tuple) = all(anynan(args), istart:iend)
|
||||
|
||||
function Base.iterate(itr::SegmentsIterator, nextidx::Int = 1)
|
||||
nextidx > itr.n && return nothing
|
||||
if nextidx == 1 && !any(isempty,itr.args) && anynan(1, itr.args)
|
||||
nextidx = 2
|
||||
end
|
||||
i = findfirst(!anynan(itr.args), nextidx:itr.n)
|
||||
i === nothing && return nothing
|
||||
nextval = nextidx + i - 1
|
||||
|
||||
i = istart = iend = nextidx
|
||||
j = findfirst(anynan(itr.args), nextval:itr.n)
|
||||
nextnan = j === nothing ? itr.n + 1 : nextval + j - 1
|
||||
|
||||
# find the next NaN, and iend is the one before
|
||||
while i <= itr.n + 1
|
||||
if i > itr.n || anynan(i, itr.args)
|
||||
# done... array end or found NaN
|
||||
iend = i-1
|
||||
break
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
|
||||
# find the next non-NaN, and set nextidx
|
||||
while i <= itr.n
|
||||
if !anynan(i, itr.args)
|
||||
break
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
|
||||
istart:iend, i
|
||||
nextval:nextnan-1, nextnan
|
||||
end
|
||||
|
||||
# Find minimal type that can contain NaN and x
|
||||
@@ -273,6 +258,9 @@ _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)
|
||||
|
||||
_as_gradient(grad::ColorGradient) = grad
|
||||
_as_gradient(c::Colorant) = ColorGradient([c,c])
|
||||
|
||||
makevec(v::AVec) = v
|
||||
makevec(v::T) where {T} = T[v]
|
||||
|
||||
@@ -283,18 +271,17 @@ maketuple(x::Tuple{T,S}) where {T,S} = x
|
||||
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
|
||||
mapFuncOrFuncs(fs::AVec{F}, u::AVec) where {F<:Function} = [map(f, u) for f in fs]
|
||||
|
||||
unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2] for t in xy]
|
||||
unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
|
||||
unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
|
||||
for i in 2:4
|
||||
@eval begin
|
||||
unzip(v::Union{AVec{<:Tuple{Vararg{T,$i} where T}},
|
||||
AVec{<:GeometryTypes.Point{$i}}}) = $(Expr(:tuple, (:([t[$j] for t in v]) for j=1:i)...))
|
||||
end
|
||||
end
|
||||
|
||||
unzip(xy::AVec{StaticArrays.SVector{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
|
||||
unzip(xy::StaticArrays.SVector{2,T}) where {T} = T[xy[1]], T[xy[2]]
|
||||
|
||||
unzip(xyz::AVec{StaticArrays.SVector{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
|
||||
unzip(xyz::StaticArrays.SVector{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
|
||||
|
||||
unzip(xyuv::AVec{StaticArrays.SVector{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
|
||||
unzip(xyuv::StaticArrays.SVector{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
|
||||
unzip(v::Union{AVec{<:GeometryTypes.Point{N}},
|
||||
AVec{<:Tuple{Vararg{T,N} where T}}}) where N = error("$N-dimensional unzip not implemented.")
|
||||
unzip(v::Union{AVec{<:GeometryTypes.Point},
|
||||
AVec{<:Tuple}}) = error("Can't unzip points of different dimensions.")
|
||||
|
||||
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
|
||||
function _expand_limits(lims, x)
|
||||
@@ -370,38 +357,14 @@ function heatmap_edges(v::AVec, scale::Symbol = :identity)
|
||||
map(invf, _heatmap_edges(map(f,v)))
|
||||
end
|
||||
|
||||
function calc_r_extrema(x, y)
|
||||
xmin, xmax = ignorenan_extrema(x)
|
||||
ymin, ymax = ignorenan_extrema(y)
|
||||
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
|
||||
ignorenan_extrema(r)
|
||||
end
|
||||
|
||||
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
||||
function convert_to_polar(theta, r, r_extrema = ignorenan_extrema(r))
|
||||
rmin, rmax = r_extrema
|
||||
theta, r = filter_radial_data(x, y, r_extrema)
|
||||
r = (r .- rmin) ./ (rmax .- rmin)
|
||||
x = r.*cos.(theta)
|
||||
y = r.*sin.(theta)
|
||||
x, y
|
||||
end
|
||||
|
||||
# Filters radial data for points within the axis limits
|
||||
function filter_radial_data(theta, r, r_extrema::Tuple{Real, Real})
|
||||
n = max(length(theta), length(r))
|
||||
rmin, rmax = r_extrema
|
||||
x, y = zeros(n), zeros(n)
|
||||
for i in 1:n
|
||||
x[i] = _cycle(theta, i)
|
||||
y[i] = _cycle(r, i)
|
||||
end
|
||||
points = map((a, b) -> (a, b), x, y)
|
||||
filter!(a -> a[2] >= rmin && a[2] <= rmax, points)
|
||||
x = map(a -> a[1], points)
|
||||
y = map(a -> a[2], points)
|
||||
x, y
|
||||
end
|
||||
|
||||
function fakedata(sz...)
|
||||
y = zeros(sz...)
|
||||
for r in 2:size(y,1)
|
||||
@@ -431,7 +394,7 @@ isvertical(series::Series) = isvertical(series.plotattributes)
|
||||
|
||||
ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
|
||||
ticksType(ticks::AVec{T}) where {T<:AbstractString} = :labels
|
||||
ticksType(ticks::Tuple{T,S}) where {T<:AVec,S<:AVec} = :ticks_and_labels
|
||||
ticksType(ticks::Tuple{T,S}) where {T<:Union{AVec,Tuple},S<:Union{AVec,Tuple}} = :ticks_and_labels
|
||||
ticksType(ticks) = :invalid
|
||||
|
||||
limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits
|
||||
@@ -527,7 +490,7 @@ function concatenate_fillrange(x,y::Tuple)
|
||||
end
|
||||
|
||||
function get_sp_lims(sp::Subplot, letter::Symbol)
|
||||
axis_limits(sp[Symbol(letter, :axis)])
|
||||
axis_limits(sp, letter)
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -564,9 +527,9 @@ function get_clims(sp::Subplot)
|
||||
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface)
|
||||
for series in series_list(sp)
|
||||
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
|
||||
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Real)
|
||||
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real})
|
||||
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals.surf)...)
|
||||
elseif (vals != nothing) && (eltype(vals) <: Real)
|
||||
elseif (vals != nothing) && (eltype(vals) <: Union{Missing, Real})
|
||||
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...)
|
||||
end
|
||||
end
|
||||
@@ -581,35 +544,50 @@ end
|
||||
|
||||
_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax)
|
||||
|
||||
function hascolorbar(series::Series)
|
||||
st = series[:seriestype]
|
||||
hascbar = st == :heatmap
|
||||
if st == :contour
|
||||
hascbar = (isscalar(series[:levels]) ? (series[:levels] > 1) : (length(series[:levels]) > 1)) && (length(unique(Array(series[:z]))) > 1)
|
||||
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
|
||||
|
||||
function colorbar_style(series::Series)
|
||||
colorbar_entry = series[:colorbar_entry]
|
||||
if !(colorbar_entry isa Bool)
|
||||
@warn "Non-boolean colorbar_entry ignored."
|
||||
colorbar_entry = true
|
||||
end
|
||||
if series[:marker_z] != nothing || series[:line_z] != nothing || series[:fill_z] != nothing
|
||||
hascbar = true
|
||||
|
||||
if !colorbar_entry
|
||||
nothing
|
||||
elseif isfilledcontour(series)
|
||||
cbar_fill
|
||||
elseif iscontour(series)
|
||||
cbar_lines
|
||||
elseif series[:seriestype] ∈ (:heatmap,:surface) ||
|
||||
any(series[z] !== nothing for z ∈ [:marker_z,:line_z,:fill_z])
|
||||
cbar_gradient
|
||||
else
|
||||
nothing
|
||||
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
|
||||
hascolorbar(series::Series) = colorbar_style(series) !== nothing
|
||||
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
|
||||
|
||||
iscontour(series::Series) = series[:seriestype] == :contour
|
||||
isfilledcontour(series::Series) = iscontour(series) && series[:fillrange] !== nothing
|
||||
|
||||
function contour_levels(series::Series, clims)
|
||||
iscontour(series) || error("Not a contour series")
|
||||
zmin, zmax = clims
|
||||
levels = series[:levels]
|
||||
if levels isa Integer
|
||||
levels = range(zmin, stop=zmax, length=levels+2)
|
||||
if !isfilledcontour(series)
|
||||
levels = levels[2:end-1]
|
||||
end
|
||||
end
|
||||
hascbar
|
||||
levels
|
||||
end
|
||||
|
||||
|
||||
|
||||
for comp in (:line, :fill, :marker)
|
||||
|
||||
compcolor = string(comp, :color)
|
||||
@@ -646,6 +624,9 @@ for comp in (:line, :fill, :marker)
|
||||
end
|
||||
end
|
||||
|
||||
single_color(c, v = 0.5) = c
|
||||
single_color(grad::ColorGradient, v = 0.5) = grad[v]
|
||||
|
||||
function get_linewidth(series, i::Int = 1)
|
||||
_cycle(series[:linewidth], i)
|
||||
end
|
||||
@@ -673,7 +654,7 @@ function has_attribute_segments(series::Series)
|
||||
end
|
||||
series[:seriestype] == :shape && return false
|
||||
# ... else we check relevant attributes if they have multiple inputs
|
||||
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z, :marker_z))
|
||||
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z))
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
@@ -796,24 +777,24 @@ function debugplots(on = true)
|
||||
_debugMode.on = on
|
||||
end
|
||||
|
||||
debugshow(x) = show(x)
|
||||
debugshow(x::AbstractArray) = print(summary(x))
|
||||
debugshow(io, x) = show(io, x)
|
||||
debugshow(io, x::AbstractArray) = print(io, summary(x))
|
||||
|
||||
function dumpdict(plotattributes::KW, prefix = "", alwaysshow = false)
|
||||
function dumpdict(io::IO, plotattributes::KW, prefix = "", alwaysshow = false)
|
||||
_debugMode.on || alwaysshow || return
|
||||
println()
|
||||
println(io)
|
||||
if prefix != ""
|
||||
println(prefix, ":")
|
||||
println(io, prefix, ":")
|
||||
end
|
||||
for k in sort(collect(keys(plotattributes)))
|
||||
@printf("%14s: ", k)
|
||||
debugshow(plotattributes[k])
|
||||
println()
|
||||
debugshow(io, plotattributes[k])
|
||||
println(io)
|
||||
end
|
||||
println()
|
||||
println(io)
|
||||
end
|
||||
DD(plotattributes::KW, prefix = "") = dumpdict(plotattributes, prefix, true)
|
||||
|
||||
DD(io::IO, plotattributes::KW, prefix = "") = dumpdict(io, plotattributes, prefix, true)
|
||||
DD(plotattributes::KW, prefix = "") = DD(stdout, plotattributes, prefix)
|
||||
|
||||
function dumpcallstack()
|
||||
error() # well... you wanted the stacktrace, didn't you?!?
|
||||
@@ -1208,8 +1189,8 @@ function _fmt_paragraph(io::IOBuffer,
|
||||
fillwidth=60,
|
||||
leadingspaces=0)
|
||||
|
||||
kwargs = (fillwidth = fillwidth, leadingspaces = leadingspaces)
|
||||
|
||||
kwargs = (fillwidth = fillwidth, leadingspaces = leadingspaces)
|
||||
|
||||
m = match(r"(.*?) (.*)",remaining_text)
|
||||
if isa(m,Nothing)
|
||||
if column_count + length(remaining_text) ≤ fillwidth
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
reference_images
|
||||
@@ -1,10 +0,0 @@
|
||||
StatsPlots
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
FileIO
|
||||
GR 0.31.0
|
||||
RDatasets
|
||||
VisualRegressionTests
|
||||
UnicodePlots
|
||||
LaTeXStrings
|
||||
@@ -1,46 +0,0 @@
|
||||
using Pkg
|
||||
|
||||
# need this to use Conda
|
||||
# ENV["PYTHON"] = ""
|
||||
|
||||
to_add = [
|
||||
# PackageSpec(url="https://github.com/JuliaStats/KernelDensity.jl.git"),
|
||||
PackageSpec(name="PlotUtils", rev="master"),
|
||||
PackageSpec(name="RecipesBase", rev="master"),
|
||||
# PackageSpec(name="Blink", rev="master"),
|
||||
# PackageSpec(name="Rsvg", rev="master"),
|
||||
# PackageSpec(name="PlotlyJS", rev="master"),
|
||||
# PackageSpec(name="VisualRegressionTests", rev="master"),
|
||||
# PackageSpec("PyPlot"),
|
||||
# PackageSpec("InspectDR"),
|
||||
]
|
||||
|
||||
if isinteractive()
|
||||
Pkg.develop(PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"))
|
||||
append!(to_add, [
|
||||
PackageSpec(name="FileIO"),
|
||||
PackageSpec(name="ImageMagick"),
|
||||
PackageSpec(name="UnicodePlots"),
|
||||
PackageSpec(name="VisualRegressionTests"),
|
||||
PackageSpec(name="Gtk"),
|
||||
# PlotlyJS:
|
||||
# PackageSpec(name="PlotlyJS"),
|
||||
# PackageSpec(name="Blink"),
|
||||
# PackageSpec(name="ORCA"),
|
||||
# PyPlot:
|
||||
# PackageSpec(name="PyPlot"),
|
||||
# PackageSpec(name="PyCall"),
|
||||
# PackageSpec(name="LaTeXStrings"),
|
||||
])
|
||||
else
|
||||
push!(to_add, PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"))
|
||||
end
|
||||
|
||||
Pkg.add(to_add)
|
||||
|
||||
Pkg.build("ImageMagick")
|
||||
# Pkg.build("GR")
|
||||
# Pkg.build("Blink")
|
||||
# import Blink
|
||||
# Blink.AtomShell.install()
|
||||
# Pkg.build("PyPlot")
|
||||
+33
-35
@@ -1,50 +1,46 @@
|
||||
|
||||
using VisualRegressionTests
|
||||
# using ExamplePlots
|
||||
|
||||
if isinteractive()
|
||||
@eval Main import Gtk
|
||||
end
|
||||
|
||||
# import DataFrames, RDatasets
|
||||
|
||||
# don't let pyplot use a gui... it'll crash
|
||||
# note: Agg will set gui -> :none in PyPlot
|
||||
# ENV["MPLBACKEND"] = "Agg"
|
||||
# try
|
||||
# @eval import PyPlot
|
||||
# @info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
|
||||
# end
|
||||
|
||||
|
||||
using Plots
|
||||
# using StatsPlots
|
||||
import PlotReferenceImages
|
||||
using Random
|
||||
using Test
|
||||
|
||||
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)
|
||||
|
||||
import Plots._current_plots_version
|
||||
|
||||
# Taken from MakieGallery
|
||||
"""
|
||||
Downloads the reference images from ReferenceImages for a specific version
|
||||
"""
|
||||
function download_reference(version = v"0.0.1")
|
||||
download_dir = abspath(@__DIR__, "reference_images")
|
||||
isdir(download_dir) || mkpath(download_dir)
|
||||
tarfile = joinpath(download_dir, "reference_images.zip")
|
||||
url = "https://github.com/JuliaPlots/PlotReferenceImages.jl/archive/v$(version).tar.gz"
|
||||
refpath = joinpath(download_dir, "PlotReferenceImages.jl-$(version)")
|
||||
if !isdir(refpath) # if not yet downloaded
|
||||
@info "downloading reference images for version $version"
|
||||
download(url, tarfile)
|
||||
BinaryProvider.unpack(tarfile, download_dir)
|
||||
# check again after download
|
||||
if !isdir(refpath)
|
||||
error("Something went wrong while downloading reference images. Plots can't be compared to references")
|
||||
else
|
||||
rm(tarfile, force = true)
|
||||
end
|
||||
else
|
||||
@info "using reference images for version $version (already downloaded)"
|
||||
end
|
||||
refpath
|
||||
end
|
||||
|
||||
const ref_image_dir = download_reference()
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2)
|
||||
Plots._debugMode.on = debug
|
||||
example = Plots._examples[idx]
|
||||
Plots.theme(:default)
|
||||
@info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
backend(pkg)
|
||||
backend()
|
||||
|
||||
default(size=(500,300))
|
||||
# ensure consistent results
|
||||
Random.seed!(1234)
|
||||
|
||||
# reference image directory setup
|
||||
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
|
||||
refdir = joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots", string(pkg))
|
||||
refdir = joinpath(ref_image_dir, "Plots", string(pkg))
|
||||
fn = "ref$idx.png"
|
||||
|
||||
# firgure out version info
|
||||
@@ -76,7 +72,9 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
|
||||
|
||||
# test function
|
||||
func = (fn, idx) -> begin
|
||||
map(eval, example.exprs)
|
||||
expr = Expr(:block)
|
||||
append!(expr.args, example.exprs)
|
||||
eval(expr)
|
||||
png(fn)
|
||||
end
|
||||
|
||||
|
||||
+50
-113
@@ -1,8 +1,12 @@
|
||||
module PlotsTests
|
||||
using VisualRegressionTests
|
||||
using Plots
|
||||
using Random
|
||||
using BinaryProvider
|
||||
using Test
|
||||
using FileIO
|
||||
using GeometryTypes
|
||||
|
||||
include("add_packages.jl")
|
||||
include("imgcomp.jl")
|
||||
|
||||
# don't actually show the plots
|
||||
Random.seed!(1234)
|
||||
default(show=false, reuse=true)
|
||||
@@ -19,85 +23,20 @@ img_tol = isinteractive() ? 1e-2 : 10e-2
|
||||
end
|
||||
end
|
||||
|
||||
# @static if isinteractive()
|
||||
# @testset "PyPlot" begin
|
||||
# @test pyplot() == Plots.PyPlotBackend()
|
||||
# @test backend() == Plots.PyPlotBackend()
|
||||
#
|
||||
# image_comparison_facts(:pyplot, tol=img_tol, skip = [2, 25, 30, 31])
|
||||
# end
|
||||
# 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
|
||||
p = plot(rand(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = bar(randn(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
end
|
||||
|
||||
# The plotlyjs testimages return a connection error on travis:
|
||||
# connect: connection refused (ECONNREFUSED)
|
||||
|
||||
# @static if isinteractive()
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# image_comparison_facts(:plotlyjs,
|
||||
# skip=[
|
||||
# 2, # animation (skipped for speed)
|
||||
# 25,
|
||||
# 27, # (polar plots) takes very long / not working
|
||||
# 30,
|
||||
# 31, # animation (skipped for speed)
|
||||
# ],
|
||||
# tol=img_tol)
|
||||
# end
|
||||
# end
|
||||
|
||||
# InspectDR returns that error on travis:
|
||||
# ERROR: LoadError: InitError: Cannot open display:
|
||||
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
|
||||
|
||||
# @testset "InspectDR" begin
|
||||
# @test inspectdr() == Plots.InspectDRBackend()
|
||||
# @test backend() == Plots.InspectDRBackend()
|
||||
#
|
||||
# image_comparison_facts(:inspectdr,
|
||||
# skip=[
|
||||
# 2, # animation
|
||||
# 6, # heatmap not defined
|
||||
# 10, # heatmap not defined
|
||||
# 22, # contour not defined
|
||||
# 23, # pie not defined
|
||||
# 27, # polar plot not working
|
||||
# 28, # heatmap not defined
|
||||
# 31, # animation
|
||||
# ],
|
||||
# tol=img_tol)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "Plotly" begin
|
||||
# @test plotly() == Plots.PlotlyBackend()
|
||||
# @test backend() == Plots.PlotlyBackend()
|
||||
#
|
||||
# # # until png generation is reliable on OSX, just test on linux
|
||||
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
|
||||
# end
|
||||
|
||||
# @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], tol=img_tol)
|
||||
# end
|
||||
|
||||
|
||||
|
||||
|
||||
@testset "Axes" begin
|
||||
p = plot()
|
||||
axis = p.subplots[1][:xaxis]
|
||||
@@ -113,46 +52,44 @@ end
|
||||
end
|
||||
|
||||
@testset "NoFail" begin
|
||||
histogram([1, 0, 0, 0, 0, 0])
|
||||
plots = [histogram([1, 0, 0, 0, 0, 0]),
|
||||
plot([missing]),
|
||||
plot([missing; 1:4]),
|
||||
plot([fill(missing,10); 1:4]),
|
||||
plot([1 1; 1 missing]),
|
||||
plot(["a" "b"; missing "d"], [1 2; 3 4])]
|
||||
for plt in plots
|
||||
display(plt)
|
||||
end
|
||||
end
|
||||
|
||||
# tests for preprocessing recipes
|
||||
@testset "Segments" begin
|
||||
function segments(args...)
|
||||
segs = UnitRange{Int}[]
|
||||
for seg in iter_segments(args...)
|
||||
push!(segs,seg)
|
||||
end
|
||||
segs
|
||||
end
|
||||
|
||||
# @testset "recipes" begin
|
||||
nan10 = fill(NaN,10)
|
||||
@test segments(11:20) == [1:10]
|
||||
@test segments([NaN]) == []
|
||||
@test segments(nan10) == []
|
||||
@test segments([nan10; 1:5]) == [11:15]
|
||||
@test segments([1:5;nan10]) == [1:5]
|
||||
@test segments([nan10; 1:5; nan10; 1:5; nan10]) == [11:15, 26:30]
|
||||
@test segments([NaN; 1], 1:10) == [2:2, 4:4, 6:6, 8:8, 10:10]
|
||||
@test segments([nan10; 1:15], [1:15; nan10]) == [11:15]
|
||||
end
|
||||
|
||||
# user recipe
|
||||
|
||||
# type T end
|
||||
# @recipe function f(::T)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# bg := :yellow
|
||||
# rand(10)
|
||||
# end
|
||||
# plot(T())
|
||||
|
||||
# plot recipe
|
||||
|
||||
# @recipe function f(::Type{Val{:hiplt}},plt::Plot)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# t := :path
|
||||
# bg:=:green
|
||||
# ()
|
||||
# end
|
||||
# plot(rand(10),t=:hiplt)
|
||||
|
||||
# series recipe
|
||||
|
||||
# @recipe function f(::Type{Val{:hi}},x,y,z)
|
||||
# line := (3,0.3,:red)
|
||||
# marker := (20,0.5,:blue,:o)
|
||||
# t := :path
|
||||
# ()
|
||||
# end
|
||||
# plot(rand(10),t=:hiplt)
|
||||
|
||||
# end
|
||||
|
||||
|
||||
end # module
|
||||
@testset "Utils" begin
|
||||
zipped = ([(1,2)], [("a","b")], [(1,"a"),(2,"b")],
|
||||
[(1,2),(3,4)], [(1,2,3),(3,4,5)], [(1,2,3,4),(3,4,5,6)],
|
||||
[(1,2.0),(missing,missing)], [(1,missing),(missing,"a")],
|
||||
[(missing,missing)], [(missing,missing,missing),("a","b","c")])
|
||||
for z in zipped
|
||||
@test isequal(collect(zip(Plots.unzip(z)...)), z)
|
||||
@test isequal(collect(zip(Plots.unzip(Point.(z))...)), z)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import SnoopCompile
|
||||
|
||||
### Log the compiles
|
||||
# This only needs to be run once (to generate "/tmp/plots_compiles.csv")
|
||||
|
||||
# SnoopCompile.@snoop "/tmp/plots_compiles.csv" begin
|
||||
# include(joinpath(dirname(@__FILE__), "runtests.jl"))
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
### Parse the compiles and generate precompilation scripts
|
||||
# This can be run repeatedly to tweak the scripts
|
||||
|
||||
# IMPORTANT: we must have the module(s) defined for the parcelation
|
||||
# step, otherwise we will get no precompiles for the Plots module
|
||||
using Plots
|
||||
|
||||
data = SnoopCompile.read("/tmp/plots_compiles.csv")
|
||||
|
||||
# The Plots tests are run inside a module PlotsTest, so all
|
||||
# the precompiles get credited to PlotsTest. Credit them to Plots instead.
|
||||
subst = Dict("PlotsTests"=>"Plots")
|
||||
|
||||
# Blacklist helps fix problems:
|
||||
# - MIME uses type-parameters with symbols like :image/png, which is
|
||||
# not parseable
|
||||
blacklist = ["MIME"]
|
||||
|
||||
# Use these two lines if you want to create precompile functions for
|
||||
# individual packages
|
||||
pc, discards = SnoopCompile.parcel(data[end:-1:1,2], subst=subst, blacklist=blacklist)
|
||||
SnoopCompile.write("/tmp/precompile", pc)
|
||||
|
||||
pdir = joinpath(dirname(@__FILE__), "..")
|
||||
run(`cp /tmp/precompile/precompile_Plots.jl $pdir/src/precompile.jl`)
|
||||
Reference in New Issue
Block a user