Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0ad66da36 | |||
| aca2aa49b8 | |||
| 9d56e72f6a | |||
| f06225655d | |||
| 4f0f84f400 | |||
| a65cda8b7e | |||
| 37744d7b6a | |||
| 09a66224ce | |||
| 405bc0820b | |||
| 1c89bd8727 | |||
| 8e17a182f9 | |||
| 032c5d1638 | |||
| 8d95333d1e | |||
| 7bfc97285c | |||
| acca707f34 | |||
| 6fa3dae166 | |||
| 866cb0c335 | |||
| 4d40bae9cc | |||
| 5a48002d31 | |||
| 0cd81243ad | |||
| ed3bab0e6f | |||
| 4621c18b23 | |||
| 4f8a265c6a | |||
| e2539a3d19 | |||
| 85739932f0 | |||
| 9d84e53bcb | |||
| 82f31c48b7 | |||
| 81571fe534 | |||
| 293b8b112e | |||
| d988d4c9d1 | |||
| 85bd3ea53f | |||
| cd6a8c87b6 | |||
| 175c87cec6 | |||
| c3f45dd712 | |||
| 198a59b621 | |||
| c5d7283473 | |||
| 7a1bc88f66 | |||
| ad5cd2f1da | |||
| 6cf01229bb | |||
| 0a9d30f7ac | |||
| 7da990b23f | |||
| 942fb38dcd | |||
| 7ba99d1b06 | |||
| 6b82a82d04 | |||
| 7c882a7288 | |||
| 5343873f72 | |||
| e3a5f2b11e | |||
| 34758c82a3 | |||
| 748104c807 | |||
| 0d2bc3f227 | |||
| c45352d153 | |||
| b833b6582a | |||
| b28a261b39 | |||
| 1a1cc08992 | |||
| 31d33e6be4 | |||
| 2dc812aa15 | |||
| bdbe300412 | |||
| 70b635dbe1 | |||
| 1e44dd7035 | |||
| 4744152f86 | |||
| dc51f2c159 | |||
| cc1f662b3a | |||
| 7b77527f80 | |||
| 8b6073c088 | |||
| 09d35d7b9f | |||
| 0a9da21443 | |||
| ea686c331b | |||
| 25a36bab85 | |||
| b227fb8943 | |||
| 22651e8728 | |||
| 5acf967a9e | |||
| 5afeba656b | |||
| 7b8bd5b253 | |||
| ded808477d | |||
| 854d5ba5c9 | |||
| 07a619e5ae | |||
| 1426c95fd4 | |||
| 52ec432cfa | |||
| 0742d475bc | |||
| 10802baf6e | |||
| c67da7d7b8 | |||
| f85f668f18 | |||
| c4208c7560 | |||
| 35fd604e07 | |||
| 214663aa4b | |||
| d56a03975f |
@@ -20,10 +20,11 @@ Backend | yes | no | untested
|
||||
-------------|-----|-----|---------
|
||||
gr (default) | | |
|
||||
pyplot | | |
|
||||
plotly | | |
|
||||
plotlyjs | | |
|
||||
pgfplotsx | | |
|
||||
unicodeplots | | |
|
||||
inspectdr | | |
|
||||
gaston | | |
|
||||
|
||||
### Versions
|
||||
|
||||
|
||||
@@ -76,10 +76,11 @@ jobs:
|
||||
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots")'
|
||||
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes")'
|
||||
|
||||
- name: Codecov
|
||||
uses: julia-actions/julia-uploadcodecov@latest
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
# Codecov
|
||||
- uses: julia-actions/julia-processcoverage@v1
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: lcov.info
|
||||
|
||||
Skip:
|
||||
if: "contains(github.event.head_commit.message, '[skip ci]')"
|
||||
|
||||
@@ -13,14 +13,10 @@ jobs:
|
||||
with:
|
||||
version: 1
|
||||
|
||||
# Setup
|
||||
- name: Ubuntu TESTCMD
|
||||
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
|
||||
|
||||
# Check format
|
||||
- name: Install JuliaFormatter and format
|
||||
run: |
|
||||
git diff --name-only --exit-code
|
||||
$TESTCMD -e 'using Pkg; pkg"add JuliaFormatter CSTParser#master"'
|
||||
$TESTCMD -e 'using JuliaFormatter; format(["src", "test"])'
|
||||
julia -e 'using Pkg; pkg"add JuliaFormatter CSTParser#master"'
|
||||
julia -e 'using JuliaFormatter; [format(["src", "test"]) for _ in 1:2]'
|
||||
git diff --exit-code
|
||||
@@ -0,0 +1,35 @@
|
||||
name: format-pr
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * SUN'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install JuliaFormatter and format
|
||||
run: |
|
||||
julia -e 'using Pkg; pkg"add JuliaFormatter CSTParser#master"'
|
||||
julia -e 'using JuliaFormatter; [format(["src", "test"]) for _ in 1:2]'
|
||||
git diff --exit-code
|
||||
|
||||
- name: Create Pull Request
|
||||
if: ${{ failure() }}
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "Format .jl files [skip ci]"
|
||||
title: 'Automatic JuliaFormatter.jl run'
|
||||
branch: auto-juliaformatter-pr
|
||||
delete-branch: true
|
||||
labels: formatting, automated pr, no changelog
|
||||
|
||||
- name: Check outputs
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
||||
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||
+11
-1
@@ -688,10 +688,20 @@
|
||||
{
|
||||
"name": "@t-bltg",
|
||||
"type": "Other"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Fred Callaway",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"name": "Jan Thorben Schneider",
|
||||
"type": "Other"
|
||||
},
|
||||
{
|
||||
"orcid": "0000-0003-4102-2460",
|
||||
"affiliation": "Alogus Research Corporation",
|
||||
"name": "Lee Phillips",
|
||||
"type": "Other"
|
||||
}
|
||||
],
|
||||
"upload_type": "software"
|
||||
|
||||
+9
-7
@@ -1,12 +1,13 @@
|
||||
name = "Plots"
|
||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
author = ["Tom Breloff (@tbreloff)"]
|
||||
version = "1.20.1"
|
||||
version = "1.22.4"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
|
||||
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
|
||||
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
|
||||
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
|
||||
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
|
||||
@@ -34,23 +35,24 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||
|
||||
[compat]
|
||||
Contour = "0.5"
|
||||
FFMPEG = "0.2, 0.3, 0.4"
|
||||
FixedPointNumbers = "0.6, 0.7, 0.8"
|
||||
GR = "0.53, 0.54, 0.55, 0.57, 0.58"
|
||||
FFMPEG = "0.2 - 0.4"
|
||||
FixedPointNumbers = "0.6 - 0.8"
|
||||
GR = "0.53 - 0.59"
|
||||
GeometryBasics = "0.2, 0.3.1, 0.4"
|
||||
JSON = "0.21, 1"
|
||||
Latexify = "0.14, 0.15"
|
||||
Latexify = "0.14 - 0.15"
|
||||
Measures = "0.3"
|
||||
NaNMath = "0.3"
|
||||
PlotThemes = "2"
|
||||
PlotUtils = "1"
|
||||
RecipesBase = "1"
|
||||
RecipesPipeline = "0.3"
|
||||
RecipesPipeline = "0.3.5, 0.4"
|
||||
Reexport = "0.2, 1.0"
|
||||
Requires = "1"
|
||||
Scratch = "1"
|
||||
Showoff = "0.3.1, 1.0"
|
||||
StatsBase = "0.32, 0.33"
|
||||
StatsBase = "0.32 - 0.33"
|
||||
UnicodePlots = "2.4"
|
||||
julia = "1.5"
|
||||
|
||||
[extras]
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[gitter-url]: https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
|
||||
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
|
||||
[docs-url]: http://docs.juliaplots.org/latest/
|
||||
[docs-url]: https://docs.juliaplots.org/latest/
|
||||
|
||||
[![][gh-ci-img]][gh-ci-url]
|
||||
[![][pkgeval-img]][pkgeval-url]
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
github_checks:
|
||||
annotations: false
|
||||
|
||||
ignore:
|
||||
- "src/backends/inspectdr.jl"
|
||||
- "src/backends/orca.jl"
|
||||
|
||||
+33
-9
@@ -76,6 +76,8 @@ function _precompile_()
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Tuple{Int64, Int64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Vector{Int64}}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:flip,), Tuple{Bool}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,), Tuple{Symbol}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,), Tuple{typeof(datetimeformatter)}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :flip, :minorgrid, :guide), Tuple{Bool, Bool, Bool, String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims), Tuple{Bool, Tuple{Float64, Float64}}},typeof(attr!),Axis})
|
||||
@@ -92,6 +94,7 @@ function _precompile_()
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Int64, Float64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Int64, Int64}}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:minorgrid, :scale, :guide), Tuple{Bool, Symbol, String}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:minorgrid,), Tuple{Bool}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:rotation,), Tuple{Int64}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,), Tuple{Nothing}},typeof(attr!),Axis})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,), Tuple{UnitRange{Int64}}},typeof(attr!),Axis})
|
||||
@@ -123,6 +126,7 @@ function _precompile_()
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),Plot{PlotlyBackend},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Plot{GRBackend},Vector{Int64},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64},Vector{Float64}})
|
||||
@@ -135,6 +139,8 @@ function _precompile_()
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:title,), Tuple{String}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:w,), Tuple{Int64}},typeof(plot!),Plot{GRBackend},Vector{Float64},Vector{Float64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:xgrid,), Tuple{Tuple{Symbol, Symbol, Int64, Symbol, Float64}}},typeof(plot!),Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!),Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!),Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!)})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Float64}})
|
||||
@@ -151,6 +157,7 @@ function _precompile_()
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:lab, :w, :palette, :fill, :α), Tuple{String, Int64, PlotUtils.ContinuousColorGradient, Int64, Float64}},typeof(plot),StepRange{Int64, Int64},Matrix{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label, :title, :xlabel, :linewidth, :legend), Tuple{Matrix{String}, String, String, Int64, Symbol}},typeof(plot),Vector{Function},Float64,Float64})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label,), Tuple{Matrix{String}}},typeof(plot),Vector{AbstractVector{Float64}}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:labels,), Tuple{Matrix{String}}},typeof(plot),PortfolioComposition})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :group, :linetype, :linecolor), Tuple{GridLayout, Vector{String}, Matrix{Symbol}, Symbol}},typeof(plot),Vector{Float64}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
@@ -230,7 +237,7 @@ function _precompile_()
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{GRBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{PlotlyBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plot{GRBackend},DefaultsDict})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_axis_args!),Plot{GRBackend},Dict{Symbol, Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_axis_args!),Plot{PlotlyBackend},Dict{Symbol, Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{GRBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
|
||||
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},DefaultsDict,Symbol,Any})
|
||||
@@ -243,14 +250,16 @@ function _precompile_()
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{PlotUtils.ContinuousColorGradient},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}},String})
|
||||
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Symbol},String})
|
||||
Base.precompile(Tuple{typeof(_cycle),Base.OneTo{Int64},Vector{Int64}})
|
||||
Base.precompile(Tuple{typeof(_cycle),StepRange{Int64, Int64},Vector{Int64}})
|
||||
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},StepRange{Int64, Int64}})
|
||||
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},Vector{Int64}})
|
||||
Base.precompile(Tuple{typeof(_do_plot_show),Plot{GRBackend},Bool})
|
||||
Base.precompile(Tuple{typeof(_do_plot_show),Plot{PlotlyBackend},Bool})
|
||||
Base.precompile(Tuple{typeof(_heatmap_edges),Vector{Float64},Bool,Bool})
|
||||
Base.precompile(Tuple{typeof(_plot!),Plot,Any,Any})
|
||||
Base.precompile(Tuple{typeof(_preprocess_barlike),DefaultsDict,Base.OneTo{Int64},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(_preprocess_binlike),DefaultsDict,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(_slice_series_args!),DefaultsDict,Plot{GRBackend},Subplot{GRBackend},Int64})
|
||||
Base.precompile(Tuple{typeof(_update_min_padding!),GridLayout})
|
||||
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{GRBackend},Subplot{GRBackend},Dict{Symbol, Any},Int64,Bool})
|
||||
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{PlotlyBackend},Subplot{PlotlyBackend},Dict{Symbol, Any},Int64,Bool})
|
||||
@@ -268,9 +277,11 @@ function _precompile_()
|
||||
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(error_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
|
||||
Base.precompile(Tuple{typeof(fakedata),Int64,Int64})
|
||||
Base.precompile(Tuple{typeof(get_clims),Subplot{GRBackend},Series,Function})
|
||||
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Vector{Float64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Vector{Int64}, Vector{String}}})
|
||||
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{GRBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{PlotlyBackend},Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(get_ticks),StepRange{Int64, Int64},Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Float64},Vararg{Any, N} where N})
|
||||
@@ -280,20 +291,16 @@ function _precompile_()
|
||||
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), NTuple{9, Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), Tuple{Int64, Int64, Int64, Float64, Int64, Float64, Float64, Float64, Float64}},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_display),Subplot{GRBackend},AbsoluteLength,AbsoluteLength,Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_colorbar),GRColorbar,Subplot{GRBackend},Tuple{Float64, Float64},Vector{Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_contour),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_heatmap),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Float64,Float64,Symbol})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Shape{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Float64,Tuple{Float64, Float64},Int64,Float64,Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Int64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
|
||||
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Base.OneTo{Int64},Vector{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Vector{Int64},Vector{Int64},Tuple{Float64, Float64},Int64,Int64})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},UnitRange{Int64},Tuple{Vector{Float64}, Vector{Float64}},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,StepRange{Int64, Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Vector{Float64},Vector{Float64},Int64,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_shapes),Series,Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Vector{Float64},Tuple{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(gr_fill_viewport),Vector{Float64},RGBA{Float64}})
|
||||
@@ -328,14 +335,15 @@ function _precompile_()
|
||||
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend}})
|
||||
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
|
||||
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
|
||||
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol, Any},Float64,Symbol})
|
||||
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol, Any},Symbol,Symbol})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Matrix{Symbol}})
|
||||
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Matrix{Symbol}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},RGBA{Float64}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Shape{Float64, Float64}})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Stroke})
|
||||
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Symbol})
|
||||
Base.precompile(Tuple{typeof(processMinorGridArg!),Dict{Symbol, Any},Bool,Symbol})
|
||||
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,PlotText})
|
||||
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
|
||||
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
|
||||
@@ -349,21 +357,37 @@ function _precompile_()
|
||||
Base.precompile(Tuple{typeof(scalefontsizes),Float64})
|
||||
Base.precompile(Tuple{typeof(series_annotations),Vector{Any}})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{AbsoluteLength},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{Bool},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{Int64},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{PlotUtils.ContinuousColorGradient},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{RGBA{Float64}},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{String},Int64})
|
||||
Base.precompile(Tuple{typeof(slice_arg),Matrix{Symbol},Int64})
|
||||
Base.precompile(Tuple{typeof(spy),Any})
|
||||
Base.precompile(Tuple{typeof(straightline_data),Tuple{Float64, Float64},Tuple{Float64, Float64},Vector{Float64},Vector{Float64},Int64})
|
||||
Base.precompile(Tuple{typeof(stroke),Int64,Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(title!),AbstractString})
|
||||
Base.precompile(Tuple{typeof(unzip),Vector{GeometryBasics.Point2{Float64}}})
|
||||
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Float64, Float64, Float64}}})
|
||||
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Float64, Float64}}})
|
||||
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Int64, Int64}}})
|
||||
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Vector{Float64}, Vector{Float64}}}})
|
||||
Base.precompile(Tuple{typeof(vline!),Any})
|
||||
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any, N} where N})
|
||||
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
|
||||
isdefined(Plots, Symbol("#add_major_or_minor_segments#126")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#126")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
|
||||
isdefined(Plots, Symbol("#add_major_or_minor_segments#127")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#127")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
|
||||
isdefined(Plots, Symbol("#add_major_or_minor_segments#120")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#120")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
|
||||
isdefined(Plots, Symbol("#add_major_or_minor_segments#121")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#121")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
|
||||
let fbody = try __lookup_kwbody__(which(font, (Font,Vararg{Any, N} where N,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(font),Font,Vararg{Any, N} where N,))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(gr_polyline, (Vector{Float64},Vector{Float64},typeof(GR.fillarea),))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Symbol,Symbol,typeof(gr_polyline),Vector{Float64},Vector{Float64},typeof(GR.fillarea),))
|
||||
end
|
||||
end
|
||||
let fbody = try __lookup_kwbody__(which(plot!, (Any,))) catch missing end
|
||||
if !ismissing(fbody)
|
||||
precompile(fbody, (Any,typeof(plot!),Any,))
|
||||
|
||||
@@ -31,6 +31,7 @@ using Base.Meta
|
||||
@reexport using PlotThemes
|
||||
import Showoff
|
||||
import StatsBase
|
||||
import Downloads
|
||||
import JSON
|
||||
|
||||
using Requires
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ const _arg_desc = KW(
|
||||
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
|
||||
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
|
||||
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
|
||||
:fillstyle => "Symbol. Style of the fill area. `nothing` (the default) means solid fill. Choose from :/, :\\, :|, :-, :+, :x",
|
||||
:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.",
|
||||
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
|
||||
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers",
|
||||
@@ -30,7 +31,7 @@ const _arg_desc = KW(
|
||||
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
|
||||
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
|
||||
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
|
||||
:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.",
|
||||
:levels => "Integer (number of contours) or AbstractVector (contour values). Determines contour levels for a contour type.",
|
||||
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
|
||||
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
|
||||
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
|
||||
|
||||
+178
-106
@@ -24,6 +24,14 @@ function add_aliases(sym::Symbol, aliases::Symbol...)
|
||||
return nothing
|
||||
end
|
||||
|
||||
function add_axes_aliases(sym::Symbol, aliases::Symbol...; generic::Bool = true)
|
||||
sym in keys(_axis_defaults) || throw(ArgumentError("Invalid `$sym`"))
|
||||
generic && add_aliases(sym, aliases...)
|
||||
for letter in (:x, :y, :z)
|
||||
add_aliases(Symbol(letter, sym), (Symbol(letter, a) for a in aliases)...)
|
||||
end
|
||||
end
|
||||
|
||||
function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
|
||||
for (k, v) in aliases
|
||||
s = string(k)
|
||||
@@ -276,7 +284,7 @@ function hasgrid(arg::Symbol, letter)
|
||||
arg in (:all, :both, :on) || occursin(string(letter), string(arg))
|
||||
else
|
||||
@warn(
|
||||
"Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead."
|
||||
"Unknown grid argument $arg; $(get_attr_symbol(letter, :grid)) was set to `true` instead."
|
||||
)
|
||||
true
|
||||
end
|
||||
@@ -316,7 +324,7 @@ function showaxis(arg::Symbol, letter)
|
||||
arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg))
|
||||
else
|
||||
@warn(
|
||||
"Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead."
|
||||
"Unknown showaxis argument $arg; $(get_attr_symbol(letter, :showaxis)) was set to `true` instead."
|
||||
)
|
||||
true
|
||||
end
|
||||
@@ -348,6 +356,7 @@ const _series_defaults = KW(
|
||||
:fillrange => nothing, # ribbons, areas, etc
|
||||
:fillcolor => :match,
|
||||
:fillalpha => nothing,
|
||||
:fillstyle => nothing,
|
||||
:markershape => :none,
|
||||
:markercolor => :match,
|
||||
:markeralpha => nothing,
|
||||
@@ -570,11 +579,6 @@ function reset_axis_defaults_byletter!()
|
||||
end
|
||||
reset_axis_defaults_byletter!()
|
||||
|
||||
for letter in (:x, :y, :z), k in keys(_axis_defaults)
|
||||
# allow the underscore version too: xguide or x_guide
|
||||
add_aliases(Symbol(letter, k), Symbol(letter, "_", k))
|
||||
end
|
||||
|
||||
const _all_defaults = KW[_series_defaults, _plot_defaults, _subplot_defaults]
|
||||
|
||||
const _initial_defaults = deepcopy(_all_defaults)
|
||||
@@ -619,6 +623,20 @@ const _all_subplot_args = sort(union([_subplot_args; _magic_subplot_args]))
|
||||
const _all_series_args = sort(union([_series_args; _magic_series_args]))
|
||||
const _all_plot_args = _plot_args
|
||||
|
||||
for letter in (:x, :y, :z)
|
||||
_attrsymbolcache[letter] = Dict{Symbol,Symbol}()
|
||||
for k in keys(_axis_defaults)
|
||||
# populate attribute cache
|
||||
lk = Symbol(letter, k)
|
||||
_attrsymbolcache[letter][k] = lk
|
||||
# allow the underscore version too: xguide or x_guide
|
||||
add_aliases(lk, Symbol(letter, "_", k))
|
||||
end
|
||||
for k in (_magic_axis_args..., :(_discrete_indices))
|
||||
_attrsymbolcache[letter][k] = Symbol(letter, k)
|
||||
end
|
||||
end
|
||||
|
||||
const _all_args =
|
||||
sort(union([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args]))
|
||||
|
||||
@@ -754,30 +772,7 @@ add_aliases(
|
||||
:fgcolour_subplot,
|
||||
:fg_colour_subplot,
|
||||
)
|
||||
add_aliases(
|
||||
:foreground_color_grid,
|
||||
:fg_grid,
|
||||
:fggrid,
|
||||
:fgcolor_grid,
|
||||
:fg_color_grid,
|
||||
:foreground_grid,
|
||||
:foreground_colour_grid,
|
||||
:fgcolour_grid,
|
||||
:fg_colour_grid,
|
||||
:gridcolor,
|
||||
)
|
||||
add_aliases(
|
||||
:foreground_color_minor_grid,
|
||||
:fg_minor_grid,
|
||||
:fgminorgrid,
|
||||
:fgcolor_minorgrid,
|
||||
:fg_color_minorgrid,
|
||||
:foreground_minorgrid,
|
||||
:foreground_colour_minor_grid,
|
||||
:fgcolour_minorgrid,
|
||||
:fg_colour_minor_grid,
|
||||
:minorgridcolor,
|
||||
)
|
||||
|
||||
add_aliases(
|
||||
:foreground_color_title,
|
||||
:fg_title,
|
||||
@@ -845,7 +840,80 @@ add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
|
||||
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
|
||||
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
|
||||
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
|
||||
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
|
||||
|
||||
# axes attributes
|
||||
add_axes_aliases(:guide, :label, :lab, :l; generic = false)
|
||||
add_axes_aliases(:lims, :lim, :limit, :limits, :range)
|
||||
add_axes_aliases(:ticks, :tick)
|
||||
add_axes_aliases(:rotation, :rot, :r)
|
||||
add_axes_aliases(:guidefontsize, :labelfontsize)
|
||||
add_axes_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
|
||||
add_axes_aliases(
|
||||
:gridstyle,
|
||||
:grid_style,
|
||||
:gridlinestyle,
|
||||
:grid_linestyle,
|
||||
:grid_ls,
|
||||
:gridls,
|
||||
)
|
||||
add_axes_aliases(
|
||||
:foreground_color_grid,
|
||||
:fg_grid,
|
||||
:fggrid,
|
||||
:fgcolor_grid,
|
||||
:fg_color_grid,
|
||||
:foreground_grid,
|
||||
:foreground_colour_grid,
|
||||
:fgcolour_grid,
|
||||
:fg_colour_grid,
|
||||
:gridcolor,
|
||||
)
|
||||
add_axes_aliases(
|
||||
:foreground_color_minor_grid,
|
||||
:fg_minor_grid,
|
||||
:fgminorgrid,
|
||||
:fgcolor_minorgrid,
|
||||
:fg_color_minorgrid,
|
||||
:foreground_minorgrid,
|
||||
:foreground_colour_minor_grid,
|
||||
:fgcolour_minorgrid,
|
||||
:fg_colour_minor_grid,
|
||||
:minorgridcolor,
|
||||
)
|
||||
add_axes_aliases(
|
||||
:gridlinewidth,
|
||||
:gridwidth,
|
||||
:grid_linewidth,
|
||||
:grid_width,
|
||||
:gridlw,
|
||||
:grid_lw,
|
||||
)
|
||||
add_axes_aliases(
|
||||
:minorgridstyle,
|
||||
:minorgrid_style,
|
||||
:minorgridlinestyle,
|
||||
:minorgrid_linestyle,
|
||||
:minorgrid_ls,
|
||||
:minorgridls,
|
||||
)
|
||||
add_axes_aliases(
|
||||
:minorgridlinewidth,
|
||||
:minorgridwidth,
|
||||
:minorgrid_linewidth,
|
||||
:minorgrid_width,
|
||||
:minorgridlw,
|
||||
:minorgrid_lw,
|
||||
)
|
||||
add_axes_aliases(
|
||||
:tick_direction,
|
||||
:tickdirection,
|
||||
:tick_dir,
|
||||
:tickdir,
|
||||
:tick_orientation,
|
||||
:tickorientation,
|
||||
:tick_or,
|
||||
:tickor,
|
||||
)
|
||||
|
||||
# series attributes
|
||||
add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt)
|
||||
@@ -864,19 +932,7 @@ add_aliases(:group, :g, :grouping)
|
||||
add_aliases(:bins, :bin, :nbin, :nbins, :nb)
|
||||
add_aliases(:ribbon, :rib)
|
||||
add_aliases(:annotations, :ann, :anns, :annotate, :annotation)
|
||||
add_aliases(:xguide, :xlabel, :xlab, :xl)
|
||||
add_aliases(:xlims, :xlim, :xlimit, :xlimits, :xrange)
|
||||
add_aliases(:xticks, :xtick)
|
||||
add_aliases(:xrotation, :xrot, :xr)
|
||||
add_aliases(:yguide, :ylabel, :ylab, :yl)
|
||||
add_aliases(:ylims, :ylim, :ylimit, :ylimits, :yrange)
|
||||
add_aliases(:yticks, :ytick)
|
||||
add_aliases(:yrotation, :yrot, :yr)
|
||||
add_aliases(:zguide, :zlabel, :zlab, :zl)
|
||||
add_aliases(:zlims, :zlim, :zlimit, :zlimits)
|
||||
add_aliases(:zticks, :ztick)
|
||||
add_aliases(:zrotation, :zrot, :zr)
|
||||
add_aliases(:guidefontsize, :labelfontsize)
|
||||
|
||||
add_aliases(
|
||||
:fill_z,
|
||||
:fillz,
|
||||
@@ -945,24 +1001,7 @@ add_aliases(:html_output_format, :format, :fmt, :html_format)
|
||||
add_aliases(:orientation, :direction, :dir)
|
||||
add_aliases(:inset_subplots, :inset, :floating)
|
||||
add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str)
|
||||
add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw)
|
||||
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
|
||||
add_aliases(
|
||||
:minorgridlinewidth,
|
||||
:minorgridwidth,
|
||||
:minorgrid_linewidth,
|
||||
:minorgrid_width,
|
||||
:minorgridlw,
|
||||
:minorgrid_lw,
|
||||
)
|
||||
add_aliases(
|
||||
:minorgridstyle,
|
||||
:minorgrid_style,
|
||||
:minorgridlinestyle,
|
||||
:minorgrid_linestyle,
|
||||
:minorgrid_ls,
|
||||
:minorgridls,
|
||||
)
|
||||
|
||||
add_aliases(
|
||||
:framestyle,
|
||||
:frame_style,
|
||||
@@ -976,16 +1015,7 @@ add_aliases(
|
||||
:border_style,
|
||||
:border,
|
||||
)
|
||||
add_aliases(
|
||||
:tick_direction,
|
||||
:tickdirection,
|
||||
:tick_dir,
|
||||
:tickdir,
|
||||
:tick_orientation,
|
||||
:tickorientation,
|
||||
:tick_or,
|
||||
:tickor,
|
||||
)
|
||||
|
||||
add_aliases(:camera, :cam, :viewangle, :view_angle)
|
||||
add_aliases(:contour_labels, :contourlabels, :clabels, :clabs)
|
||||
add_aliases(:warn_on_unsupported, :warn)
|
||||
@@ -1117,6 +1147,7 @@ function processLineArg(plotattributes::AKW, arg)
|
||||
arg.color == :auto ? :auto : plot_color(arg.color)
|
||||
)
|
||||
arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha)
|
||||
arg.style === nothing || (plotattributes[:fillstyle] = arg.style)
|
||||
|
||||
elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows)
|
||||
plotattributes[:arrow] = arg
|
||||
@@ -1188,6 +1219,7 @@ function processFillArg(plotattributes::AKW, arg)
|
||||
arg.color == :auto ? :auto : plot_color(arg.color)
|
||||
)
|
||||
arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha)
|
||||
arg.style === nothing || (plotattributes[:fillstyle] = arg.style)
|
||||
|
||||
elseif typeof(arg) <: Bool
|
||||
plotattributes[:fillrange] = arg ? 0 : nothing
|
||||
@@ -1213,69 +1245,79 @@ end
|
||||
|
||||
function processGridArg!(plotattributes::AKW, arg, letter)
|
||||
if arg in _allGridArgs || isa(arg, Bool)
|
||||
plotattributes[Symbol(letter, :grid)] = hasgrid(arg, letter)
|
||||
plotattributes[get_attr_symbol(letter, :grid)] = hasgrid(arg, letter)
|
||||
|
||||
elseif allStyles(arg)
|
||||
plotattributes[Symbol(letter, :gridstyle)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :gridstyle)] = arg
|
||||
|
||||
elseif typeof(arg) <: Stroke
|
||||
arg.width === nothing ||
|
||||
(plotattributes[Symbol(letter, :gridlinewidth)] = arg.width)
|
||||
(plotattributes[get_attr_symbol(letter, :gridlinewidth)] = arg.width)
|
||||
arg.color === nothing || (
|
||||
plotattributes[Symbol(letter, :foreground_color_grid)] =
|
||||
plotattributes[get_attr_symbol(letter, :foreground_color_grid)] =
|
||||
arg.color in (:auto, :match) ? :match : plot_color(arg.color)
|
||||
)
|
||||
arg.alpha === nothing || (plotattributes[Symbol(letter, :gridalpha)] = arg.alpha)
|
||||
arg.style === nothing || (plotattributes[Symbol(letter, :gridstyle)] = arg.style)
|
||||
arg.alpha === nothing ||
|
||||
(plotattributes[get_attr_symbol(letter, :gridalpha)] = arg.alpha)
|
||||
arg.style === nothing ||
|
||||
(plotattributes[get_attr_symbol(letter, :gridstyle)] = arg.style)
|
||||
|
||||
# linealpha
|
||||
elseif allAlphas(arg)
|
||||
plotattributes[Symbol(letter, :gridalpha)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :gridalpha)] = arg
|
||||
|
||||
# linewidth
|
||||
elseif allReals(arg)
|
||||
plotattributes[Symbol(letter, :gridlinewidth)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :gridlinewidth)] = arg
|
||||
|
||||
# color
|
||||
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_grid))
|
||||
elseif !handleColors!(
|
||||
plotattributes,
|
||||
arg,
|
||||
get_attr_symbol(letter, :foreground_color_grid),
|
||||
)
|
||||
@warn("Skipped grid arg $arg.")
|
||||
end
|
||||
end
|
||||
|
||||
function processMinorGridArg!(plotattributes::AKW, arg, letter)
|
||||
if arg in _allGridArgs || isa(arg, Bool)
|
||||
plotattributes[Symbol(letter, :minorgrid)] = hasgrid(arg, letter)
|
||||
plotattributes[get_attr_symbol(letter, :minorgrid)] = hasgrid(arg, letter)
|
||||
|
||||
elseif allStyles(arg)
|
||||
plotattributes[Symbol(letter, :minorgridstyle)] = arg
|
||||
plotattributes[Symbol(letter, :minorgrid)] = true
|
||||
plotattributes[get_attr_symbol(letter, :minorgridstyle)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
|
||||
|
||||
elseif typeof(arg) <: Stroke
|
||||
arg.width === nothing ||
|
||||
(plotattributes[Symbol(letter, :minorgridlinewidth)] = arg.width)
|
||||
(plotattributes[get_attr_symbol(letter, :minorgridlinewidth)] = arg.width)
|
||||
arg.color === nothing || (
|
||||
plotattributes[Symbol(letter, :foreground_color_minor_grid)] =
|
||||
plotattributes[get_attr_symbol(letter, :foreground_color_minor_grid)] =
|
||||
arg.color in (:auto, :match) ? :match : plot_color(arg.color)
|
||||
)
|
||||
arg.alpha === nothing ||
|
||||
(plotattributes[Symbol(letter, :minorgridalpha)] = arg.alpha)
|
||||
(plotattributes[get_attr_symbol(letter, :minorgridalpha)] = arg.alpha)
|
||||
arg.style === nothing ||
|
||||
(plotattributes[Symbol(letter, :minorgridstyle)] = arg.style)
|
||||
plotattributes[Symbol(letter, :minorgrid)] = true
|
||||
(plotattributes[get_attr_symbol(letter, :minorgridstyle)] = arg.style)
|
||||
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
|
||||
|
||||
# linealpha
|
||||
elseif allAlphas(arg)
|
||||
plotattributes[Symbol(letter, :minorgridalpha)] = arg
|
||||
plotattributes[Symbol(letter, :minorgrid)] = true
|
||||
plotattributes[get_attr_symbol(letter, :minorgridalpha)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
|
||||
|
||||
# linewidth
|
||||
elseif allReals(arg)
|
||||
plotattributes[Symbol(letter, :minorgridlinewidth)] = arg
|
||||
plotattributes[Symbol(letter, :minorgrid)] = true
|
||||
plotattributes[get_attr_symbol(letter, :minorgridlinewidth)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
|
||||
|
||||
# color
|
||||
elseif handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_minor_grid))
|
||||
plotattributes[Symbol(letter, :minorgrid)] = true
|
||||
elseif handleColors!(
|
||||
plotattributes,
|
||||
arg,
|
||||
get_attr_symbol(letter, :foreground_color_minor_grid),
|
||||
)
|
||||
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
|
||||
else
|
||||
@warn("Skipped grid arg $arg.")
|
||||
end
|
||||
@@ -1341,7 +1383,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
|
||||
end
|
||||
# handle axis args
|
||||
for letter in (:x, :y, :z)
|
||||
asym = Symbol(letter, :axis)
|
||||
asym = get_attr_symbol(letter, :axis)
|
||||
args = RecipesPipeline.pop_kw!(plotattributes, asym, ())
|
||||
if !(typeof(args) <: Axis)
|
||||
for arg in wraptuple(args)
|
||||
@@ -1368,7 +1410,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
|
||||
end
|
||||
# handle individual axes grid args
|
||||
for letter in (:x, :y, :z)
|
||||
gridsym = Symbol(letter, :grid)
|
||||
gridsym = get_attr_symbol(letter, :grid)
|
||||
args = RecipesPipeline.pop_kw!(plotattributes, gridsym, ())
|
||||
for arg in wraptuple(args)
|
||||
processGridArg!(plotattributes, arg, letter)
|
||||
@@ -1383,7 +1425,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
|
||||
end
|
||||
# handle individual axes grid args
|
||||
for letter in (:x, :y, :z)
|
||||
gridsym = Symbol(letter, :minorgrid)
|
||||
gridsym = get_attr_symbol(letter, :minorgrid)
|
||||
args = RecipesPipeline.pop_kw!(plotattributes, gridsym, ())
|
||||
for arg in wraptuple(args)
|
||||
processMinorGridArg!(plotattributes, arg, letter)
|
||||
@@ -1394,16 +1436,20 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
|
||||
args = RecipesPipeline.pop_kw!(plotattributes, fontname, ())
|
||||
for arg in wraptuple(args)
|
||||
for letter in (:x, :y, :z)
|
||||
processFontArg!(plotattributes, Symbol(letter, fontname), arg)
|
||||
processFontArg!(plotattributes, get_attr_symbol(letter, fontname), arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
# handle individual axes font args
|
||||
for letter in (:x, :y, :z)
|
||||
for fontname in (:tickfont, :guidefont)
|
||||
args = RecipesPipeline.pop_kw!(plotattributes, Symbol(letter, fontname), ())
|
||||
args = RecipesPipeline.pop_kw!(
|
||||
plotattributes,
|
||||
get_attr_symbol(letter, fontname),
|
||||
(),
|
||||
)
|
||||
for arg in wraptuple(args)
|
||||
processFontArg!(plotattributes, Symbol(letter, fontname), arg)
|
||||
processFontArg!(plotattributes, get_attr_symbol(letter, fontname), arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1412,7 +1458,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
|
||||
if haskey(plotattributes, k) && k !== :link
|
||||
v = plotattributes[k]
|
||||
for letter in (:x, :y, :z)
|
||||
lk = Symbol(letter, k)
|
||||
lk = get_attr_symbol(letter, k)
|
||||
if !is_explicit(plotattributes, lk)
|
||||
plotattributes[lk] = v
|
||||
end
|
||||
@@ -1502,6 +1548,11 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
|
||||
plotattributes[:framestyle] = _framestyleAliases[plotattributes[:framestyle]]
|
||||
end
|
||||
|
||||
# contours
|
||||
if haskey(plotattributes, :levels)
|
||||
check_contour_levels(plotattributes[:levels])
|
||||
end
|
||||
|
||||
# warnings for moved recipes
|
||||
st = get(plotattributes, :seriestype, :path)
|
||||
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots)
|
||||
@@ -1534,7 +1585,7 @@ function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes)
|
||||
end
|
||||
|
||||
if !isempty(_to_warn) &&
|
||||
!get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported])
|
||||
get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported])
|
||||
for k in sort(collect(_to_warn))
|
||||
push!(already_warned, k)
|
||||
@warn(
|
||||
@@ -1629,6 +1680,26 @@ convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
"""Throw an error if the `levels` keyword argument is not of the correct type
|
||||
or `levels` is less than 1"""
|
||||
function check_contour_levels(levels)
|
||||
if !(levels isa Union{Integer,AVec})
|
||||
throw(
|
||||
ArgumentError(
|
||||
"the levels keyword argument must be an integer or AbstractVector",
|
||||
),
|
||||
)
|
||||
elseif levels isa Integer && levels <= 0
|
||||
throw(
|
||||
ArgumentError(
|
||||
"must pass a positive number of contours to the levels keyword argument",
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# 1-row matrices will give an element
|
||||
# multi-row matrices will give a column
|
||||
# InputWrapper just gives the contents
|
||||
@@ -1894,7 +1965,8 @@ function _update_axis(
|
||||
end
|
||||
|
||||
# then get those args that were passed with a leading letter: `xlabel = "X"`
|
||||
lk = Symbol(letter, k)
|
||||
lk = get_attr_symbol(letter, k)
|
||||
|
||||
if haskey(plotattributes_in, lk)
|
||||
kw[k] = slice_arg(plotattributes_in[lk], subplot_index)
|
||||
end
|
||||
@@ -1951,7 +2023,7 @@ function _update_subplot_args(
|
||||
lims_warned = false
|
||||
for letter in (:x, :y, :z)
|
||||
_update_axis(plt, sp, plotattributes_in, letter, subplot_index)
|
||||
lk = Symbol(letter, :lims)
|
||||
lk = get_attr_symbol(letter, :lims)
|
||||
|
||||
# warn against using `Range` in x,y,z lims
|
||||
if !lims_warned &&
|
||||
|
||||
+32
-27
@@ -23,7 +23,7 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
end
|
||||
|
||||
function get_axis(sp::Subplot, letter::Symbol)
|
||||
axissym = Symbol(letter, :axis)
|
||||
axissym = get_attr_symbol(letter, :axis)
|
||||
if haskey(sp.attr, axissym)
|
||||
sp.attr[axissym]
|
||||
else
|
||||
@@ -35,40 +35,44 @@ function process_axis_arg!(plotattributes::AKW, arg, letter = "")
|
||||
T = typeof(arg)
|
||||
arg = get(_scaleAliases, arg, arg)
|
||||
if typeof(arg) <: Font
|
||||
plotattributes[Symbol(letter, :tickfont)] = arg
|
||||
plotattributes[Symbol(letter, :guidefont)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :tickfont)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :guidefont)] = arg
|
||||
|
||||
elseif arg in _allScales
|
||||
plotattributes[Symbol(letter, :scale)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :scale)] = arg
|
||||
|
||||
elseif arg in (:flip, :invert, :inverted)
|
||||
plotattributes[Symbol(letter, :flip)] = true
|
||||
plotattributes[get_attr_symbol(letter, :flip)] = true
|
||||
|
||||
elseif T <: AbstractString
|
||||
plotattributes[Symbol(letter, :guide)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :guide)] = arg
|
||||
|
||||
# xlims/ylims
|
||||
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
|
||||
sym = typeof(arg[1]) <: Number ? :lims : :ticks
|
||||
plotattributes[Symbol(letter, sym)] = arg
|
||||
plotattributes[get_attr_symbol(letter, sym)] = arg
|
||||
|
||||
# xticks/yticks
|
||||
elseif T <: AVec
|
||||
plotattributes[Symbol(letter, :ticks)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :ticks)] = arg
|
||||
|
||||
elseif arg === nothing
|
||||
plotattributes[Symbol(letter, :ticks)] = []
|
||||
plotattributes[get_attr_symbol(letter, :ticks)] = []
|
||||
|
||||
elseif T <: Bool || arg in _allShowaxisArgs
|
||||
plotattributes[Symbol(letter, :showaxis)] = showaxis(arg, letter)
|
||||
plotattributes[get_attr_symbol(letter, :showaxis)] = showaxis(arg, letter)
|
||||
|
||||
elseif typeof(arg) <: Number
|
||||
plotattributes[Symbol(letter, :rotation)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :rotation)] = arg
|
||||
|
||||
elseif typeof(arg) <: Function
|
||||
plotattributes[Symbol(letter, :formatter)] = arg
|
||||
plotattributes[get_attr_symbol(letter, :formatter)] = arg
|
||||
|
||||
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis))
|
||||
elseif !handleColors!(
|
||||
plotattributes,
|
||||
arg,
|
||||
get_attr_symbol(letter, :foreground_color_axis),
|
||||
)
|
||||
@warn("Skipped $(letter)axis arg $arg")
|
||||
end
|
||||
end
|
||||
@@ -297,7 +301,7 @@ for l in (:x, :y, :z)
|
||||
end
|
||||
end
|
||||
# get_ticks from axis symbol :x, :y, or :z
|
||||
get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[Symbol(s, :axis)])
|
||||
get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[get_attr_symbol(s, :axis)])
|
||||
get_ticks(p::Plot, s::Symbol) = [get_ticks(sp, s) for sp in p.subplots]
|
||||
|
||||
function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where {T}
|
||||
@@ -393,7 +397,7 @@ end
|
||||
|
||||
function reset_extrema!(sp::Subplot)
|
||||
for asym in (:x, :y, :z)
|
||||
sp[Symbol(asym, :axis)][:extrema] = Extrema()
|
||||
sp[get_attr_symbol(asym, :axis)][:extrema] = Extrema()
|
||||
end
|
||||
for series in sp.series_list
|
||||
expand_extrema!(sp, series.plotattributes)
|
||||
@@ -446,7 +450,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
|
||||
)
|
||||
data = [NaN]
|
||||
end
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
|
||||
if isa(data, Volume)
|
||||
expand_extrema!(sp[:xaxis], data.x_extents)
|
||||
@@ -463,7 +467,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
|
||||
# TODO: need more here... gotta track the discrete reference value
|
||||
# as well as any coord offset (think of boxplot shape coords... they all
|
||||
# correspond to the same x-value)
|
||||
plotattributes[letter], plotattributes[Symbol(letter, "_discrete_indices")] =
|
||||
plotattributes[letter],
|
||||
plotattributes[get_attr_symbol(letter, :(_discrete_indices))] =
|
||||
discrete_value!(axis, data)
|
||||
expand_extrema!(axis, plotattributes[letter])
|
||||
end
|
||||
@@ -502,7 +507,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
|
||||
plotattributes[:bar_width] =
|
||||
_bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(data))))
|
||||
end
|
||||
axis = sp.attr[Symbol(dsym, :axis)]
|
||||
axis = sp.attr[get_attr_symbol(dsym, :axis)]
|
||||
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
|
||||
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
|
||||
end
|
||||
@@ -511,8 +516,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
|
||||
if plotattributes[:seriestype] == :heatmap
|
||||
for letter in (:x, :y)
|
||||
data = plotattributes[letter]
|
||||
axis = sp[Symbol(letter, "axis")]
|
||||
scale = get(plotattributes, Symbol(letter, "scale"), :identity)
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
scale = get(plotattributes, get_attr_symbol(letter, :scale), :identity)
|
||||
expand_extrema!(axis, heatmap_edges(data, scale))
|
||||
end
|
||||
end
|
||||
@@ -586,10 +591,10 @@ end
|
||||
function axis_limits(
|
||||
sp,
|
||||
letter,
|
||||
should_widen = default_should_widen(sp[Symbol(letter, :axis)]),
|
||||
should_widen = default_should_widen(sp[get_attr_symbol(letter, :axis)]),
|
||||
consider_aspect = true,
|
||||
)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
ex = axis[:extrema]
|
||||
amin, amax = ex.emin, ex.emax
|
||||
lims = axis[:lims]
|
||||
@@ -724,10 +729,10 @@ end
|
||||
# compute the line segments which should be drawn for this axis
|
||||
function axis_drawing_info(sp, letter)
|
||||
# find out which axis we are dealing with
|
||||
asym = Symbol(letter, :axis)
|
||||
asym = get_attr_symbol(letter, :axis)
|
||||
isy = letter === :y
|
||||
oletter = isy ? :x : :y
|
||||
oasym = Symbol(oletter, :axis)
|
||||
oasym = get_attr_symbol(oletter, :axis)
|
||||
|
||||
# get axis objects, ticks and minor ticks
|
||||
ax, oax = sp[asym], sp[oasym]
|
||||
@@ -856,9 +861,9 @@ function axis_drawing_info_3d(sp, letter)
|
||||
near_letter = letter in (:x, :z) ? :y : :x
|
||||
far_letter = letter in (:x, :y) ? :z : :x
|
||||
|
||||
ax = sp[Symbol(letter, :axis)]
|
||||
nax = sp[Symbol(near_letter, :axis)]
|
||||
fax = sp[Symbol(far_letter, :axis)]
|
||||
ax = sp[get_attr_symbol(letter, :axis)]
|
||||
nax = sp[get_attr_symbol(near_letter, :axis)]
|
||||
fax = sp[get_attr_symbol(far_letter, :axis)]
|
||||
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
namin, namax = axis_limits(sp, near_letter)
|
||||
|
||||
+48
-8
@@ -247,7 +247,7 @@ function merge_with_base_supported(v::AVec)
|
||||
for vi in v
|
||||
if haskey(_axis_defaults, vi)
|
||||
for letter in (:x, :y, :z)
|
||||
push!(v, Symbol(letter, vi))
|
||||
push!(v, get_attr_symbol(letter, vi))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -402,6 +402,7 @@ const _gr_attr = merge_with_base_supported([
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
:connections,
|
||||
])
|
||||
const _gr_seriestype = [
|
||||
:path,
|
||||
@@ -521,6 +522,7 @@ const _plotly_attr = merge_with_base_supported([
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
:connections,
|
||||
])
|
||||
|
||||
const _plotly_seriestype = [
|
||||
@@ -777,6 +779,7 @@ const _pyplot_attr = merge_with_base_supported([
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
:connections,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
:path,
|
||||
@@ -793,6 +796,7 @@ const _pyplot_seriestype = [
|
||||
:contour3d,
|
||||
:path3d,
|
||||
:scatter3d,
|
||||
:mesh3d,
|
||||
:surface,
|
||||
:wireframe,
|
||||
]
|
||||
@@ -860,6 +864,7 @@ const _gaston_attr = merge_with_base_supported([
|
||||
# :framestyle,
|
||||
# :camera,
|
||||
# :contour_labels,
|
||||
:connections,
|
||||
])
|
||||
|
||||
const _gaston_seriestype = [
|
||||
@@ -910,16 +915,22 @@ const _gaston_scale = [:identity, :ln, :log2, :log10]
|
||||
# unicodeplots
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:bins,
|
||||
:guide,
|
||||
# :grid,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:seriescolor,
|
||||
:seriesalpha,
|
||||
:lims,
|
||||
:linealpha,
|
||||
:linecolor,
|
||||
:linestyle,
|
||||
:markershape,
|
||||
:bins,
|
||||
:seriesalpha,
|
||||
:seriescolor,
|
||||
:scale,
|
||||
:title,
|
||||
:guide,
|
||||
:lims,
|
||||
])
|
||||
const _unicodeplots_seriestype = [
|
||||
:path,
|
||||
@@ -928,11 +939,39 @@ const _unicodeplots_seriestype = [
|
||||
# :bar,
|
||||
:shape,
|
||||
:histogram2d,
|
||||
:heatmap,
|
||||
:spy,
|
||||
]
|
||||
const _unicodeplots_style = [:auto, :solid]
|
||||
const _unicodeplots_marker = [:none, :auto, :circle]
|
||||
const _unicodeplots_scale = [:identity]
|
||||
const _unicodeplots_marker = [
|
||||
:none,
|
||||
:auto,
|
||||
:pixel,
|
||||
# vvvvvvvvvv shapes
|
||||
:circle,
|
||||
:rect,
|
||||
:star5,
|
||||
:diamond,
|
||||
:hexagon,
|
||||
:cross,
|
||||
:xcross,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:rtriangle,
|
||||
:ltriangle,
|
||||
:pentagon,
|
||||
# :heptagon,
|
||||
# :octagon,
|
||||
:star4,
|
||||
:star6,
|
||||
# :star7,
|
||||
:star8,
|
||||
:vline,
|
||||
:hline,
|
||||
:+,
|
||||
:x,
|
||||
]
|
||||
const _unicodeplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# Additional constants
|
||||
const _canvas_type = Ref(:auto)
|
||||
@@ -1233,6 +1272,7 @@ const _pgfplotsx_attr = merge_with_base_supported([
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
:connections,
|
||||
])
|
||||
const _pgfplotsx_seriestype = [
|
||||
:path,
|
||||
|
||||
@@ -331,7 +331,7 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function pgf_axis(sp::Subplot, letter)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
style = []
|
||||
kw = KW()
|
||||
|
||||
@@ -342,7 +342,7 @@ function pgf_axis(sp::Subplot, letter)
|
||||
framestyle = pgf_framestyle(sp[:framestyle])
|
||||
|
||||
# axis guide
|
||||
kw[Symbol(letter, :label)] = axis[:guide]
|
||||
kw[get_attr_symbol(letter, :label)] = axis[:guide]
|
||||
|
||||
# axis label position
|
||||
labelpos = ""
|
||||
@@ -378,7 +378,7 @@ function pgf_axis(sp::Subplot, letter)
|
||||
# scale
|
||||
scale = axis[:scale]
|
||||
if scale in (:log2, :ln, :log10)
|
||||
kw[Symbol(letter, :mode)] = "log"
|
||||
kw[get_attr_symbol(letter, :mode)] = "log"
|
||||
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
|
||||
end
|
||||
|
||||
@@ -400,8 +400,8 @@ function pgf_axis(sp::Subplot, letter)
|
||||
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]
|
||||
kw[get_attr_symbol(letter, :min)] = lims[1]
|
||||
kw[get_attr_symbol(letter, :max)] = lims[2]
|
||||
end
|
||||
|
||||
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
|
||||
|
||||
+11
-4
@@ -225,13 +225,13 @@ function gaston_add_series(plt::Plot{GastonBackend}, series::Series)
|
||||
gsp = sp.o
|
||||
x, y, z = series[:x], series[:y], series[:z]
|
||||
st = series[:seriestype]
|
||||
|
||||
curves = []
|
||||
if gsp.dims == 2 && z === nothing
|
||||
for (n, seg) in enumerate(series_segments(series, st; check = true))
|
||||
i, rng = seg.attr_index, seg.range
|
||||
fr = _cycle(series[:fillrange], 1:length(x[rng]))
|
||||
for sc in gaston_seriesconf!(sp, series, i, n == 1)
|
||||
push!(curves, Gaston.Curve(x[rng], y[rng], nothing, nothing, sc))
|
||||
push!(curves, Gaston.Curve(x[rng], y[rng], nothing, fr, sc))
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -304,8 +304,15 @@ function gaston_seriesconf!(
|
||||
pt, ps, mc = gaston_mk_ms_mc(series, clims, i)
|
||||
push!(curveconf, "w points pt $pt ps $ps lc $mc")
|
||||
elseif st ∈ (:path, :straightline, :path3d)
|
||||
fr = series[:fillrange]
|
||||
fc = gaston_color(get_fillcolor(series, i), get_fillalpha(series, i))
|
||||
lc, dt, lw = gaston_lc_ls_lw(series, clims, i)
|
||||
if series[:markershape] == :none # simplepath
|
||||
if fr !== nothing # filled curves, but not filled curves with markers
|
||||
push!(
|
||||
curveconf,
|
||||
"w filledcurves fc $fc fs solid border lc $lc lw $lw dt $dt,'' w lines lc $lc lw $lw dt $dt",
|
||||
)
|
||||
elseif series[:markershape] == :none # simplepath
|
||||
push!(curveconf, "w lines lc $lc dt $dt lw $lw")
|
||||
else
|
||||
pt, ps, mc = gaston_mk_ms_mc(series, clims, i)
|
||||
@@ -365,7 +372,7 @@ function gaston_parse_axes_args(
|
||||
|
||||
for letter in (:x, :y, :z)
|
||||
(letter == :z && dims == 2) && continue
|
||||
axis = sp.attr[Symbol(letter, :axis)]
|
||||
axis = sp.attr[get_attr_symbol(letter, :axis)]
|
||||
# label names
|
||||
push!(
|
||||
axesconf,
|
||||
|
||||
+127
-61
@@ -136,6 +136,12 @@ gr_set_arrowstyle(s::Symbol) = GR.setarrowstyle(
|
||||
),
|
||||
)
|
||||
|
||||
gr_set_fillstyle(::Nothing) = GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
function gr_set_fillstyle(s::Symbol)
|
||||
GR.setfillintstyle(GR.INTSTYLE_HATCH)
|
||||
GR.setfillstyle(get(((/) = 9, (\) = 10, (|) = 7, (-) = 8, (+) = 11, (x) = 6), s, 9))
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
# draw line segments, splitting x/y into contiguous/finite segments
|
||||
@@ -664,32 +670,20 @@ function gr_display(plt::Plot, fmt = "")
|
||||
end
|
||||
|
||||
function gr_set_tickfont(sp, letter)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
|
||||
# invalidate alignment changes for small rotations (|θ| < 45°)
|
||||
trigger(rot) = abs(sind(rot)) < abs(cosd(rot)) ? 0 : sign(rot)
|
||||
|
||||
rot = axis[:rotation]
|
||||
if letter === :x || (RecipesPipeline.is3d(sp) && letter === :y)
|
||||
halign = (:left, :hcenter, :right)[trigger(rot) + 2]
|
||||
valign = (axis[:mirror] ? :bottom : :top, :vcenter)[trigger(abs(rot)) + 1]
|
||||
else
|
||||
halign = (axis[:mirror] ? :left : :right, :hcenter)[trigger(abs(rot)) + 1]
|
||||
valign = (:top, :vcenter, :bottom)[trigger(rot) + 2]
|
||||
end
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
gr_set_font(
|
||||
tickfont(axis),
|
||||
sp,
|
||||
halign = halign,
|
||||
valign = valign,
|
||||
rotation = axis[:rotation],
|
||||
color = axis[:tickfontcolor],
|
||||
)
|
||||
end
|
||||
|
||||
# size of the text with no rotation
|
||||
function gr_text_size(str)
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
GR.setcharup(0, 1)
|
||||
xs, ys = gr_inqtext(0, 0, string(str))
|
||||
l, r = extrema(xs)
|
||||
b, t = extrema(ys)
|
||||
@@ -699,9 +693,11 @@ function gr_text_size(str)
|
||||
return w, h
|
||||
end
|
||||
|
||||
# size of the text with rotation applied
|
||||
function gr_text_size(str, rot)
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
GR.setcharup(0, 1)
|
||||
xs, ys = gr_inqtext(0, 0, string(str))
|
||||
l, r = extrema(xs)
|
||||
b, t = extrema(ys)
|
||||
@@ -714,12 +710,21 @@ end
|
||||
text_box_width(w, h, rot) = abs(cosd(rot)) * w + abs(cosd(rot + 90)) * h
|
||||
text_box_height(w, h, rot) = abs(sind(rot)) * w + abs(sind(rot + 90)) * h
|
||||
|
||||
function gr_get_3d_axis_angle(cvs, nt, ft, letter)
|
||||
length(cvs) < 2 && return 0
|
||||
tickpoints = [gr_w3tondc(sort_3d_axes(cv, nt, ft, letter)...) for cv ∈ cvs]
|
||||
|
||||
dx = tickpoints[2][1] - tickpoints[1][1]
|
||||
dy = tickpoints[2][2] - tickpoints[1][2]
|
||||
return atand(dy, dx)
|
||||
end
|
||||
|
||||
function gr_get_ticks_size(ticks, rot)
|
||||
w, h = 0.0, 0.0
|
||||
for (cv, dv) in zip(ticks...)
|
||||
wi, hi = gr_text_size(dv, rot)
|
||||
w = max(w, wi)
|
||||
h = max(h, hi)
|
||||
w = NaNMath.max(w, wi)
|
||||
h = NaNMath.max(h, hi)
|
||||
end
|
||||
return w, h
|
||||
end
|
||||
@@ -1058,7 +1063,9 @@ function gr_add_legend(sp, leg, viewport_plotarea)
|
||||
series[:ribbon] === nothing
|
||||
)
|
||||
fc = get_fillcolor(series, clims)
|
||||
gr_set_fill(fc) #, series[:fillalpha])
|
||||
gr_set_fill(fc)
|
||||
fs = get_fillstyle(series, i)
|
||||
gr_set_fillstyle(fs)
|
||||
l, r = xpos - leg.width_factor * 3.5, xpos - leg.width_factor / 2
|
||||
b, t = ypos - 0.4 * leg.dy, ypos + 0.4 * leg.dy
|
||||
x = [l, r, r, l, l]
|
||||
@@ -1448,7 +1455,7 @@ end
|
||||
|
||||
function gr_draw_axis(sp, letter, viewport_plotarea)
|
||||
ax = axis_drawing_info(sp, letter)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
|
||||
# draw segments
|
||||
gr_draw_grid(sp, axis, ax.grid_segments)
|
||||
@@ -1464,7 +1471,7 @@ end
|
||||
|
||||
function gr_draw_axis_3d(sp, letter, viewport_plotarea)
|
||||
ax = axis_drawing_info_3d(sp, letter)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
|
||||
# draw segments
|
||||
gr_draw_grid(sp, axis, ax.grid_segments, gr_polyline3d)
|
||||
@@ -1545,20 +1552,42 @@ function gr_draw_ticks(sp, axis, segments, func = gr_polyline)
|
||||
end
|
||||
|
||||
function gr_label_ticks(sp, letter, ticks)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
isy = letter === :y
|
||||
oletter = isy ? :x : :y
|
||||
oaxis = sp[Symbol(oletter, :axis)]
|
||||
oaxis = sp[get_attr_symbol(oletter, :axis)]
|
||||
oamin, oamax = axis_limits(sp, oletter)
|
||||
gr_set_tickfont(sp, letter)
|
||||
out_factor = ifelse(axis[:tick_direction] === :out, 1.5, 1)
|
||||
x_offset = isy ? -1.5e-2 * out_factor : 0
|
||||
y_offset = isy ? 0 : -8e-3 * out_factor
|
||||
|
||||
x_base_offset = isy ? -1.5e-2 * out_factor : 0
|
||||
y_base_offset = isy ? 0 : -8e-3 * out_factor
|
||||
|
||||
rot = axis[:rotation] % 360
|
||||
ov = sp[:framestyle] == :origin ? 0 : xor(oaxis[:flip], axis[:mirror]) ? oamax : oamin
|
||||
sgn = axis[:mirror] ? -1 : 1
|
||||
sgn2 = iseven(Int(floor(rot / 90))) ? -1 : 1
|
||||
sgn3 = if isy
|
||||
-360 < rot < -180 || 0 < rot < 180 ? 1 : -1
|
||||
else
|
||||
rot < -270 || -90 < rot < 90 || rot > 270 ? 1 : -1
|
||||
end
|
||||
for (cv, dv) in zip(ticks...)
|
||||
x, y = GR.wctondc(reverse_if((cv, ov), isy)...)
|
||||
sz_rot = gr_text_size(dv, rot)
|
||||
sz = gr_text_size(dv)
|
||||
x_offset = x_base_offset
|
||||
y_offset = y_base_offset
|
||||
if isy
|
||||
x_offset += -first(sz_rot) / 2
|
||||
if rot % 90 != 0
|
||||
y_offset += sgn2 * last(sz_rot) / 2 + sgn3 * last(sz) * cosd(rot) / 2
|
||||
end
|
||||
else
|
||||
if rot % 90 != 0
|
||||
x_offset += sgn2 * first(sz_rot) / 2 + sgn3 * last(sz) * sind(rot) / 2
|
||||
end
|
||||
y_offset += -last(sz_rot) / 2
|
||||
end
|
||||
gr_text(x + sgn * x_offset, y + sgn * y_offset, dv)
|
||||
end
|
||||
end
|
||||
@@ -1569,19 +1598,22 @@ function gr_label_ticks_3d(sp, letter, ticks)
|
||||
near_letter = letter in (:x, :z) ? :y : :x
|
||||
far_letter = letter in (:x, :y) ? :z : :x
|
||||
|
||||
ax = sp[Symbol(letter, :axis)]
|
||||
nax = sp[Symbol(near_letter, :axis)]
|
||||
fax = sp[Symbol(far_letter, :axis)]
|
||||
isy = letter === :y
|
||||
isz = letter === :z
|
||||
|
||||
ax = sp[get_attr_symbol(letter, :axis)]
|
||||
nax = sp[get_attr_symbol(near_letter, :axis)]
|
||||
fax = sp[get_attr_symbol(far_letter, :axis)]
|
||||
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
namin, namax = axis_limits(sp, near_letter)
|
||||
famin, famax = axis_limits(sp, far_letter)
|
||||
n0, n1 = letter === :y ? (namax, namin) : (namin, namax)
|
||||
n0, n1 = isy ? (namax, namin) : (namin, namax)
|
||||
|
||||
# find out which axes we are dealing with
|
||||
i = findfirst(==(letter), (:x, :y, :z))
|
||||
letters = axes_shift((:x, :y, :z), 1 - i)
|
||||
asyms = Symbol.(letters, :axis)
|
||||
asyms = get_attr_symbol.(letters, :axis)
|
||||
|
||||
# get axis objects, ticks and minor ticks
|
||||
# regardless of the `letter` we now use the convention that `x` in variable names refer to
|
||||
@@ -1593,32 +1625,57 @@ function gr_label_ticks_3d(sp, letter, ticks)
|
||||
nt = sp[:framestyle] == :origin ? 0 : ax[:mirror] ? n1 : n0
|
||||
ft = sp[:framestyle] == :origin ? 0 : ax[:mirror] ? famax : famin
|
||||
|
||||
xoffset = if letter === :x
|
||||
(sp[:yaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:xaxis][:tick_direction] == :out ? 1.5 : 1)
|
||||
elseif letter === :y
|
||||
(sp[:yaxis][:mirror] ? -1 : 1) * 1e-2 * (sp[:yaxis][:tick_direction] == :out ? 1.5 : 1)
|
||||
else
|
||||
(sp[:zaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:zaxis][:tick_direction] == :out ? 1.5 : 1)
|
||||
end
|
||||
yoffset = if letter === :x
|
||||
(sp[:xaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:xaxis][:tick_direction] == :out ? 1.5 : 1)
|
||||
elseif letter === :y
|
||||
(sp[:yaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:yaxis][:tick_direction] == :out ? 1.5 : 1)
|
||||
else
|
||||
0
|
||||
end
|
||||
rot = mod(ax[:rotation], 360)
|
||||
sgn = ax[:mirror] ? -1 : 1
|
||||
|
||||
cvs, dvs = ticks
|
||||
ax[:flip] && reverse!(cvs)
|
||||
|
||||
axisθ = isz ? 270 : mod(gr_get_3d_axis_angle(cvs, nt, ft, letter), 360) # issue: doesn't work with 1 tick
|
||||
axisϕ = mod(axisθ - 90, 360)
|
||||
|
||||
out_factor = ifelse(ax[:tick_direction] === :out, 1.5, 1)
|
||||
axisoffset = out_factor * 1.2e-2
|
||||
x_base_offset = axisoffset * cosd(axisϕ)
|
||||
y_base_offset = axisoffset * sind(axisϕ)
|
||||
|
||||
sgn2a = sgn2b = sgn3 = 0
|
||||
if axisθ != 0 || rot % 90 != 0
|
||||
sgn2a = (axisθ != 90) &&
|
||||
(axisθ == 0 && (rot < 90 || 180 ≤ rot < 270)) ||
|
||||
(axisθ == 270) ||
|
||||
(axisθ < 90 && (axisθ < rot < 90 || axisθ + 180 < rot < 270)) ||
|
||||
(axisθ > 270 && (rot < 90 || axisθ - 180 < rot < 270 || rot > axisθ)) ? -1 : 1
|
||||
end
|
||||
|
||||
if (axisθ - 90) % 180 != 0 || (rot - 90) % 180 != 0
|
||||
sgn2b = axisθ == 0 ||
|
||||
(axisθ == 90 && (90 ≤ rot < 180 || 270 ≤ rot < 360)) ||
|
||||
(axisθ == 270 && (rot < 90 || 180 ≤ rot < 270)) ||
|
||||
(axisθ < 90 && (axisθ < rot < 180 || axisθ + 180 < rot)) ||
|
||||
(axisθ > 270 && (rot < axisθ - 180 || 180 ≤ rot < axisθ)) ? -1 : 1
|
||||
end
|
||||
|
||||
if !(axisθ == 0 && rot % 180 == 0) && ((rot - 90) % 180 != 0)
|
||||
sgn3 = (axisθ == 0 && 90 < rot < 270) ||
|
||||
(axisθ == 90 && rot < 180) ||
|
||||
(axisθ == 270 && rot > 180) ||
|
||||
(axisθ < 90 && (rot < axisθ || 90 ≤ rot < 180 || axisθ + 180 < rot < 270)) ||
|
||||
(axisθ > 270 && (90 ≤ rot < axisθ - 180 || 180 ≤ rot < 270 || rot > axisθ)) ? -1 : 1
|
||||
end
|
||||
|
||||
for (cv, dv) in zip((cvs, dvs)...)
|
||||
xi, yi = gr_w3tondc(sort_3d_axes(cv, nt, ft, letter)...)
|
||||
gr_text(xi + xoffset, yi + yoffset, dv)
|
||||
sz_rot = gr_text_size(dv, rot)
|
||||
sz = gr_text_size(dv)
|
||||
x_offset = x_base_offset + sgn2a * first(sz_rot) / 2 + sgn3 * last(sz) * sind(rot) / 2
|
||||
y_offset = y_base_offset + sgn2b * last(sz_rot) / 2 + sgn3 * last(sz) * cosd(rot) / 2
|
||||
gr_text(xi + sgn * x_offset, yi + sgn * y_offset, dv)
|
||||
end
|
||||
end
|
||||
|
||||
function gr_label_axis(sp, letter, viewport_plotarea)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
mirror = axis[:mirror]
|
||||
# guide
|
||||
if axis[:guide] != ""
|
||||
@@ -1662,13 +1719,13 @@ function gr_label_axis(sp, letter, viewport_plotarea)
|
||||
end
|
||||
|
||||
function gr_label_axis_3d(sp, letter)
|
||||
ax = sp[Symbol(letter, :axis)]
|
||||
ax = sp[get_attr_symbol(letter, :axis)]
|
||||
if ax[:guide] != ""
|
||||
near_letter = letter in (:x, :z) ? :y : :x
|
||||
far_letter = letter in (:x, :y) ? :z : :x
|
||||
|
||||
nax = sp[Symbol(near_letter, :axis)]
|
||||
fax = sp[Symbol(far_letter, :axis)]
|
||||
nax = sp[get_attr_symbol(near_letter, :axis)]
|
||||
fax = sp[get_attr_symbol(far_letter, :axis)]
|
||||
|
||||
amin, amax = axis_limits(sp, letter)
|
||||
namin, namax = axis_limits(sp, near_letter)
|
||||
@@ -1824,6 +1881,8 @@ function gr_draw_segments(series, x, y, fillrange, clims)
|
||||
i, rng = segment.attr_index, segment.range
|
||||
fc = get_fillcolor(series, clims, i)
|
||||
gr_set_fillcolor(fc)
|
||||
fs = get_fillstyle(series, i)
|
||||
gr_set_fillstyle(fs)
|
||||
fx = _cycle(x, vcat(rng, reverse(rng)))
|
||||
fy = vcat(_cycle(fr_from, rng), _cycle(fr_to, reverse(rng)))
|
||||
gr_set_transparency(fc, get_fillalpha(series, i))
|
||||
@@ -1912,6 +1971,8 @@ function gr_draw_shapes(series, clims)
|
||||
# draw the interior
|
||||
fc = get_fillcolor(series, clims, i)
|
||||
gr_set_fill(fc)
|
||||
fs = get_fillstyle(series, i)
|
||||
gr_set_fillstyle(fs)
|
||||
gr_set_transparency(fc, get_fillalpha(series, i))
|
||||
GR.fillarea(xseg, yseg)
|
||||
|
||||
@@ -1947,19 +2008,23 @@ function gr_draw_surface(series, x, y, z, clims)
|
||||
e_kwargs = series[:extra_kwargs]
|
||||
st = series[:seriestype]
|
||||
if st === :surface
|
||||
fillalpha = get_fillalpha(series)
|
||||
fillcolor = get_fillcolor(series)
|
||||
# NOTE: setting nx = 0 or ny = 0 disables GR.gridit interpolation
|
||||
nx, ny = get(e_kwargs, :nx, 200), get(e_kwargs, :ny, 200)
|
||||
if length(x) == length(y) == length(z) && nx > 0 && ny > 0
|
||||
x, y, z = GR.gridit(x, y, z, nx, ny)
|
||||
end
|
||||
d_opt = get(e_kwargs, :display_option, GR.OPTION_COLORED_MESH)
|
||||
if (!isnothing(fillalpha) && fillalpha < 1) || alpha(first(fillcolor)) < 1
|
||||
gr_set_transparency(fillcolor, fillalpha)
|
||||
GR.surface(x, y, z, d_opt)
|
||||
if ndims(x) == ndims(y) == ndims(z) == 2
|
||||
GR.gr3.surface(x', y', z, GR.OPTION_3D_MESH)
|
||||
else
|
||||
GR.gr3.surface(x, y, z, d_opt)
|
||||
fillalpha = get_fillalpha(series)
|
||||
fillcolor = get_fillcolor(series)
|
||||
# NOTE: setting nx = 0 or ny = 0 disables GR.gridit interpolation
|
||||
nx, ny = get(e_kwargs, :nx, 200), get(e_kwargs, :ny, 200)
|
||||
if length(x) == length(y) == length(z) && nx > 0 && ny > 0
|
||||
x, y, z = GR.gridit(x, y, z, nx, ny)
|
||||
end
|
||||
d_opt = get(e_kwargs, :display_option, GR.OPTION_COLORED_MESH)
|
||||
if (!isnothing(fillalpha) && fillalpha < 1) || alpha(first(fillcolor)) < 1
|
||||
gr_set_transparency(fillcolor, fillalpha)
|
||||
GR.surface(x, y, z, d_opt)
|
||||
else
|
||||
GR.gr3.surface(x, y, z, d_opt)
|
||||
end
|
||||
end
|
||||
elseif st === :wireframe
|
||||
GR.setfillcolorind(0)
|
||||
@@ -2068,3 +2133,4 @@ function _display(plt::Plot{GRBackend})
|
||||
end
|
||||
|
||||
closeall(::GRBackend) = GR.emergencyclosegks()
|
||||
|
||||
|
||||
+48
-13
@@ -203,7 +203,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
|
||||
|
||||
if hascolorbar(sp)
|
||||
cticks = get_colorbar_ticks(sp)[2]
|
||||
colorbar_style = PGFPlotsX.Options("title" => sp[:colorbar_title])
|
||||
colorbar_style = PGFPlotsX.Options("ylabel" => sp[:colorbar_title])
|
||||
if sp[:colorbar] === :top
|
||||
push!(
|
||||
colorbar_style,
|
||||
@@ -512,10 +512,29 @@ function pgfx_add_series!(::Val{:heatmap}, axis, series_opt, series, series_func
|
||||
end
|
||||
|
||||
function pgfx_add_series!(::Val{:mesh3d}, axis, series_opt, series, series_func, opt)
|
||||
ptable = join(
|
||||
[string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...)],
|
||||
"\n ",
|
||||
)
|
||||
if opt[:connections] isa Tuple{Array,Array,Array}
|
||||
# 0-based indexing
|
||||
ptable = join(
|
||||
[string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...)],
|
||||
"\n ",
|
||||
)
|
||||
elseif typeof(opt[:connections]) <: AbstractVector{NTuple{3,Int}}
|
||||
# 1-based indexing
|
||||
ptable = join(
|
||||
[
|
||||
string(i - 1, " ", j - 1, " ", k - 1, "\\\\") for
|
||||
(i, j, k) in opt[:connections]
|
||||
],
|
||||
"\n ",
|
||||
)
|
||||
else
|
||||
throw(
|
||||
ArgumentError(
|
||||
"Argument connections has to be either a tuple of three arrays (0-based indexing)
|
||||
or an AbstractVector{NTuple{3,Int}} (1-based indexing).",
|
||||
),
|
||||
)
|
||||
end
|
||||
push!(
|
||||
series_opt,
|
||||
"patch" => nothing,
|
||||
@@ -1174,6 +1193,12 @@ function pgfx_sanitize_plot!(plt)
|
||||
end
|
||||
elseif value isa Union{AbstractString,AbstractVector{<:AbstractString}}
|
||||
subplot.attr[key] = pgfx_sanitize_string.(value)
|
||||
elseif value isa Axis
|
||||
for (k, v) in value.plotattributes
|
||||
if v isa Union{AbstractString,AbstractVector{<:AbstractString}}
|
||||
value.plotattributes[k] = pgfx_sanitize_string.(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1194,7 +1219,7 @@ function pgfx_sanitize_plot!(plt)
|
||||
end
|
||||
# --------------------------------------------------------------------------------------
|
||||
function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
|
||||
# turn off scaled ticks
|
||||
push!(opt, "scaled $(letter) ticks" => "false", string(letter, :label) => axis[:guide])
|
||||
@@ -1232,6 +1257,12 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
opt,
|
||||
string(letter, "label style") => PGFPlotsX.Options(
|
||||
labelpos => nothing,
|
||||
"at" => string(
|
||||
"{(ticklabel cs:",
|
||||
get((left = 0, right = 1), axis[:guidefonthalign], 0.5),
|
||||
")}",
|
||||
),
|
||||
"anchor" => "near ticklabel",
|
||||
"font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)),
|
||||
"color" => cstr,
|
||||
"draw opacity" => α,
|
||||
@@ -1279,21 +1310,25 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
|
||||
push!(opt, string(letter, "tick") => string("{", join(tick_values, ","), "}"))
|
||||
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
|
||||
# wrap the power part of label with }
|
||||
tick_labels = Vector{String}(undef, length(ticks[2]))
|
||||
tick_labels = similar(ticks[2])
|
||||
for (i, label) in enumerate(ticks[2])
|
||||
base, power = split(label, "^")
|
||||
power = string("{", power, "}")
|
||||
tick_labels[i] = string(base, "^", power)
|
||||
end
|
||||
push!(
|
||||
opt,
|
||||
string(letter, "ticklabels") =>
|
||||
string("{\$", join(tick_labels, "\$,\$"), "\$}"),
|
||||
)
|
||||
if tick_labels isa Vector{String}
|
||||
push!(
|
||||
opt,
|
||||
string(letter, "ticklabels") =>
|
||||
string("{\$", join(tick_labels, "\$,\$"), "\$}"),
|
||||
)
|
||||
elseif tick_labels isa Vector{LaTeXString}
|
||||
push!(opt, string(letter, "ticklabels") => join(tick_labels))
|
||||
end
|
||||
elseif axis[:showaxis]
|
||||
tick_labels =
|
||||
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
|
||||
if axis[:formatter] in (:scientific, :auto)
|
||||
if axis[:formatter] in (:scientific, :auto) && tick_labels isa Vector{String}
|
||||
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
|
||||
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
|
||||
end
|
||||
|
||||
+43
-8
@@ -362,6 +362,7 @@ end
|
||||
|
||||
function plotly_legend_pos(pos::Symbol)
|
||||
xleft = 0.07
|
||||
xright = 1.0
|
||||
ybot = 0.07
|
||||
ytop = 1.0
|
||||
xcenter = 0.55
|
||||
@@ -372,14 +373,14 @@ function plotly_legend_pos(pos::Symbol)
|
||||
xouterright = 1.05
|
||||
xouterleft = -0.15
|
||||
plotly_legend_position_mapping = (
|
||||
right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"),
|
||||
right = (coords = [xright, ycenter], xanchor = "right", yanchor = "middle"),
|
||||
left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"),
|
||||
top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"),
|
||||
bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"),
|
||||
bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"),
|
||||
bottomright = (coords = [1.0, ybot], xanchor = "right", yanchor = "bottom"),
|
||||
topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"),
|
||||
topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"),
|
||||
bottomright = (coords = [xright, ybot], xanchor = "right", yanchor = "bottom"),
|
||||
topright = (coords = [xright, ytop], xanchor = "right", yanchor = "top"),
|
||||
topleft = (coords = [xleft, ytop], xanchor = "left", yanchor = "top"),
|
||||
outertop = (coords = [center, youtertop], xanchor = "upper", yanchor = "middle"),
|
||||
outerbottom = (coords = [center, youterbot], xanchor = "lower", yanchor = "middle"),
|
||||
outerleft = (coords = [xouterleft, center], xanchor = "left", yanchor = "top"),
|
||||
@@ -400,7 +401,7 @@ function plotly_legend_pos(pos::Symbol)
|
||||
xanchor = "lower",
|
||||
yanchor = "right",
|
||||
),
|
||||
default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto"),
|
||||
default = (coords = [xright, ytop], xanchor = "auto", yanchor = "auto"),
|
||||
)
|
||||
|
||||
legend_position =
|
||||
@@ -499,7 +500,7 @@ function plotly_close_shapes(x, y)
|
||||
end
|
||||
|
||||
function plotly_data(series::Series, letter::Symbol, data)
|
||||
axis = series[:subplot][Symbol(letter, :axis)]
|
||||
axis = series[:subplot][get_attr_symbol(letter, :axis)]
|
||||
|
||||
data = if axis[:ticks] == :native && data !== nothing
|
||||
plotly_native_data(axis, data)
|
||||
@@ -617,11 +618,34 @@ function plotly_series(plt::Plot, series::Series)
|
||||
filled = isfilledcontour(series)
|
||||
plotattributes_out[:type] = "contour"
|
||||
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
|
||||
plotattributes_out[:ncontours] = series[:levels] + 2
|
||||
plotattributes_out[:contours] = KW(
|
||||
:coloring => filled ? "fill" : "lines",
|
||||
:showlabels => series[:contour_labels] == true,
|
||||
)
|
||||
# Plotly does not support arbitrary sets of contours
|
||||
# (https://github.com/plotly/plotly.js/issues/4503)
|
||||
# so we distinguish AbstractRanges and AbstractVectors
|
||||
let levels = series[:levels]
|
||||
if levels isa AbstractRange
|
||||
plotattributes_out[:contours][:start] = first(levels)
|
||||
plotattributes_out[:contours][:end] = last(levels)
|
||||
plotattributes_out[:contours][:size] = step(levels)
|
||||
elseif levels isa AVec
|
||||
levels_range =
|
||||
range(first(levels), stop = last(levels), length = length(levels))
|
||||
plotattributes_out[:contours][:start] = first(levels_range)
|
||||
plotattributes_out[:contours][:end] = last(levels_range)
|
||||
plotattributes_out[:contours][:size] = step(levels_range)
|
||||
@warn(
|
||||
"setting arbitrary contour levels with Plotly backend is not supported; " *
|
||||
"use a range to set equally-spaced contours or an integer to set the " *
|
||||
"approximate number of contours with the keyword `levels`. " *
|
||||
"Setting levels to $(levels_range)"
|
||||
)
|
||||
elseif levels isa Integer
|
||||
plotattributes_out[:ncontours] = levels + 2
|
||||
end
|
||||
end
|
||||
plotattributes_out[:colorscale] =
|
||||
plotly_colorscale(series[:linecolor], series[:linealpha])
|
||||
plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series)
|
||||
@@ -655,6 +679,7 @@ function plotly_series(plt::Plot, series::Series)
|
||||
|
||||
if series[:connections] !== nothing
|
||||
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
|
||||
# 0-based indexing
|
||||
i, j, k = series[:connections]
|
||||
if !(length(i) == length(j) == length(k))
|
||||
throw(
|
||||
@@ -666,10 +691,20 @@ function plotly_series(plt::Plot, series::Series)
|
||||
plotattributes_out[:i] = i
|
||||
plotattributes_out[:j] = j
|
||||
plotattributes_out[:k] = k
|
||||
elseif typeof(series[:connections]) <: AbstractVector{NTuple{3,Int}}
|
||||
# 1-based indexing
|
||||
i, j, k = broadcast(
|
||||
i -> [inds[i] - 1 for inds in series[:connections]],
|
||||
(1, 2, 3),
|
||||
)
|
||||
plotattributes_out[:i] = i
|
||||
plotattributes_out[:j] = j
|
||||
plotattributes_out[:k] = k
|
||||
else
|
||||
throw(
|
||||
ArgumentError(
|
||||
"Argument connections has to be a tuple of three arrays.",
|
||||
"Argument connections has to be either a tuple of three arrays (0-based indexing)
|
||||
or an AbstractVector{NTuple{3,Int}} (1-based indexing).",
|
||||
),
|
||||
)
|
||||
end
|
||||
|
||||
+246
-112
@@ -24,11 +24,30 @@ pycollections = PyPlot.pyimport("matplotlib.collections")
|
||||
pyart3d = PyPlot.art3D
|
||||
pyrcparams = PyPlot.PyDict(PyPlot.matplotlib."rcParams")
|
||||
|
||||
# "support" matplotlib v1.5
|
||||
# "support" matplotlib v3.4
|
||||
if PyPlot.version < v"3.4"
|
||||
@warn("""You are using Matplotlib $(PyPlot.version), which is no longer
|
||||
officialy supported by the Plots community. To ensure smooth Plots.jl
|
||||
integration update your Matplotlib library to a version >= 3.4.0
|
||||
|
||||
If you have used Conda.jl to install PyPlot (default installation),
|
||||
upgrade your matplotlib via Conda.jl and rebuild the PyPlot.
|
||||
|
||||
If you are not sure, here are the default instructions:
|
||||
|
||||
In Julia REPL:
|
||||
```
|
||||
import Pkg;
|
||||
Pkg.add("Conda")
|
||||
import Conda
|
||||
Conda.update()
|
||||
Pkg.build("PyPlot")
|
||||
```
|
||||
|
||||
""")
|
||||
end
|
||||
|
||||
set_facecolor_sym = if PyPlot.version < v"2"
|
||||
@warn(
|
||||
"You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0"
|
||||
)
|
||||
:set_axis_bgcolor
|
||||
else
|
||||
:set_facecolor
|
||||
@@ -60,6 +79,14 @@ end
|
||||
# # anything else just gets a bluesred gradient
|
||||
# py_colormap(c, α=nothing) = py_colormap(default_gradient(), α)
|
||||
|
||||
for k in (:linthresh, :base, :label)
|
||||
# add PyPlot specific symbols to cache
|
||||
_attrsymbolcache[k] = Dict{Symbol,Symbol}()
|
||||
for letter in (:x, :y, :z, Symbol(""), :top, :bottom, :left, :right)
|
||||
_attrsymbolcache[k][letter] = Symbol(k, letter)
|
||||
end
|
||||
end
|
||||
|
||||
py_handle_surface(v) = v
|
||||
py_handle_surface(z::Surface) = z.surf
|
||||
|
||||
@@ -162,6 +189,25 @@ function py_fillstepstyle(seriestype::Symbol)
|
||||
return nothing
|
||||
end
|
||||
|
||||
py_fillstyle(::Nothing) = nothing
|
||||
py_fillstyle(fillstyle::Symbol) = string(fillstyle)
|
||||
|
||||
function py_get_matching_math_font(parent_fontfamily)
|
||||
# matplotlib supported math fonts according to
|
||||
# https://matplotlib.org/stable/tutorials/text/mathtext.html
|
||||
py_math_supported_fonts = Dict{String,String}(
|
||||
"sans-serif" => "dejavusans",
|
||||
"serif" => "dejavuserif",
|
||||
"cm" => "cm",
|
||||
"stix" => "stix",
|
||||
"stixsans" => "stixsans",
|
||||
)
|
||||
# Fallback to "dejavusans" or "dejavuserif" in case the parentfont is different
|
||||
# from supported by matplotlib fonts
|
||||
matching_font(font) = occursin("serif", lowercase(font)) ? "dejavuserif" : "dejavusans"
|
||||
return get(py_math_supported_fonts, parent_fontfamily, matching_font(parent_fontfamily))
|
||||
end
|
||||
|
||||
# # untested... return a FontProperties object from a Plots.Font
|
||||
# function py_font(font::Font)
|
||||
# pyfont["FontProperties"](
|
||||
@@ -390,8 +436,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
elseif isvector(levels)
|
||||
extrakw[:levels] = levels
|
||||
()
|
||||
else
|
||||
error("Only numbers and vectors are supported with levels keyword")
|
||||
end
|
||||
|
||||
# add custom frame shapes to markershape?
|
||||
@@ -654,6 +698,50 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
end
|
||||
|
||||
if st == :mesh3d
|
||||
polygons = if series[:connections] isa AbstractVector{<:AbstractVector{Int}}
|
||||
# Combination of any polygon types
|
||||
broadcast(inds -> broadcast(i -> [x[i], y[i], z[i]], inds), series[:connections])
|
||||
elseif series[:connections] isa AbstractVector{NTuple{N,Int}} where {N}
|
||||
# Only N-gons - connections have to be 1-based (indexing)
|
||||
broadcast(inds -> broadcast(i -> [x[i], y[i], z[i]], inds), series[:connections])
|
||||
elseif series[:connections] isa NTuple{3,<:AbstractVector{Int}}
|
||||
# Only triangles - connections have to be 0-based (indexing)
|
||||
ci, cj, ck = series[:connections]
|
||||
if !(length(ci) == length(cj) == length(ck))
|
||||
throw(
|
||||
ArgumentError(
|
||||
"Argument connections must consist of equally sized arrays.",
|
||||
),
|
||||
)
|
||||
end
|
||||
broadcast(
|
||||
j -> broadcast(i -> [x[i], y[i], z[i]], [ci[j] + 1, cj[j] + 1, ck[j] + 1]),
|
||||
eachindex(ci),
|
||||
)
|
||||
else
|
||||
throw(
|
||||
ArgumentError(
|
||||
"Unsupported `:connections` type $(typeof(series[:connections])) for seriestype=$st",
|
||||
),
|
||||
)
|
||||
end
|
||||
col = mplot3d.art3d.Poly3DCollection(
|
||||
polygons,
|
||||
linewidths = py_thickness_scale(plt, series[:linewidth]),
|
||||
edgecolor = py_color(get_linecolor(series)),
|
||||
facecolor = py_color(series[:fillcolor]),
|
||||
alpha = get_fillalpha(series),
|
||||
zorder = series[:series_plotindex],
|
||||
)
|
||||
handle = ax."add_collection3d"(col)
|
||||
# Fix for handle: https://stackoverflow.com/questions/54994600/pyplot-legend-poly3dcollection-object-has-no-attribute-edgecolors2d
|
||||
# It seems there aren't two different alpha values for edge and face
|
||||
handle._facecolors2d = py_color(series[:fillcolor])
|
||||
handle._edgecolors2d = py_color(get_linecolor(series))
|
||||
push!(handles, handle)
|
||||
end
|
||||
|
||||
if st == :image
|
||||
xmin, xmax = ignorenan_extrema(series[:x])
|
||||
ymin, ymax = ignorenan_extrema(series[:y])
|
||||
@@ -711,24 +799,45 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
for segment in series_segments(series)
|
||||
i, rng = segment.attr_index, segment.range
|
||||
if length(rng) > 1
|
||||
lc = get_linecolor(series, clims, i)
|
||||
la = get_linealpha(series, i)
|
||||
ls = get_linestyle(series, i)
|
||||
fc = get_fillcolor(series, clims, i)
|
||||
fa = get_fillalpha(series, i)
|
||||
fs = get_fillstyle(series, i)
|
||||
has_fs = !isnothing(fs)
|
||||
|
||||
path = pypath."Path"(hcat(x[rng], y[rng]))
|
||||
|
||||
# shape outline (and potentially solid fill)
|
||||
patches = pypatches."PathPatch"(
|
||||
path;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex],
|
||||
edgecolor = py_color(
|
||||
get_linecolor(series, clims, i),
|
||||
get_linealpha(series, i),
|
||||
),
|
||||
facecolor = py_color(
|
||||
get_fillcolor(series, clims, i),
|
||||
get_fillalpha(series, i),
|
||||
),
|
||||
edgecolor = py_color(lc, la),
|
||||
facecolor = py_color(fc, has_fs ? 0 : fa),
|
||||
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
|
||||
linestyle = py_linestyle(st, get_linestyle(series, i)),
|
||||
fill = true,
|
||||
linestyle = py_linestyle(st, ls),
|
||||
fill = !has_fs,
|
||||
)
|
||||
push!(handle, ax."add_patch"(patches))
|
||||
|
||||
# shape hatched fill
|
||||
# hatch color/alpha are controlled by edge (not face) color/alpha
|
||||
if has_fs
|
||||
patches = pypatches."PathPatch"(
|
||||
path;
|
||||
label = "",
|
||||
zorder = series[:series_plotindex],
|
||||
edgecolor = py_color(fc, fa),
|
||||
facecolor = py_color(fc, 0), # don't fill with solid background
|
||||
hatch = py_fillstyle(fs),
|
||||
linewidth = 0, # don't replot shape outline (doesn't affect hatch linewidth)
|
||||
linestyle = py_linestyle(st, ls),
|
||||
fill = false,
|
||||
)
|
||||
push!(handle, ax."add_patch"(patches))
|
||||
end
|
||||
end
|
||||
end
|
||||
push!(handles, handle)
|
||||
@@ -756,16 +865,23 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng)
|
||||
end
|
||||
|
||||
la = get_linealpha(series, i)
|
||||
fc = get_fillcolor(series, clims, i)
|
||||
fa = get_fillalpha(series, i)
|
||||
fs = get_fillstyle(series, i)
|
||||
has_fs = !isnothing(fs)
|
||||
|
||||
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),
|
||||
),
|
||||
# hatch color/alpha are controlled by edge (not face) color/alpha
|
||||
# if has_fs, set edge color/alpha <- fill color/alpha and face alpha <- 0
|
||||
edgecolor = py_color(fc, has_fs ? fa : la),
|
||||
facecolor = py_color(fc, has_fs ? 0 : fa),
|
||||
hatch = py_fillstyle(fs),
|
||||
linewidths = 0,
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -787,22 +903,13 @@ function py_set_lims(ax, sp::Subplot, axis::Axis)
|
||||
getproperty(ax, Symbol("set_", letter, "lim"))(lfrom, lto)
|
||||
end
|
||||
|
||||
function py_surround_latextext(latexstring, env)
|
||||
if !isempty(latexstring) && latexstring[1] == '$' && latexstring[end] == '$'
|
||||
unenclosed = latexstring[2:(end - 1)]
|
||||
else
|
||||
unenclosed = latexstring
|
||||
end
|
||||
PyPlot.LaTeXStrings.latexstring(env, "{", unenclosed, "}")
|
||||
end
|
||||
|
||||
function py_set_ticks(sp, ax, ticks, letter, env)
|
||||
function py_set_ticks(sp, ax, ticks, letter)
|
||||
ticks == :auto && return
|
||||
axis = getproperty(ax, Symbol(letter, "axis"))
|
||||
axis = getproperty(ax, get_attr_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
|
||||
kw[dir] = kw[get_attr_symbol(:label, dir)] = false
|
||||
end
|
||||
axis."set_tick_params"(; which = "both", kw...)
|
||||
return
|
||||
@@ -813,14 +920,7 @@ function py_set_ticks(sp, ax, ticks, letter, env)
|
||||
axis."set_ticks"(ticks)
|
||||
elseif ttype == :ticks_and_labels
|
||||
axis."set_ticks"(ticks[1])
|
||||
|
||||
if get(sp[:extra_kwargs], :rawticklabels, false)
|
||||
tick_labels = ticks[2]
|
||||
else
|
||||
tick_labels = [py_surround_latextext(ticklabel, env) for ticklabel in ticks[2]]
|
||||
end
|
||||
|
||||
axis."set_ticklabels"(tick_labels)
|
||||
axis."set_ticklabels"(ticks[2])
|
||||
else
|
||||
error("Invalid input for $(letter)ticks: $ticks")
|
||||
end
|
||||
@@ -858,15 +958,15 @@ function py_set_scale(ax, sp::Subplot, scale::Symbol, letter::Symbol)
|
||||
arg = if scale == :identity
|
||||
"linear"
|
||||
else
|
||||
kw[Symbol(:base, pyletter)] = if scale == :ln
|
||||
kw[get_attr_symbol(:base, pyletter)] = if scale == :ln
|
||||
ℯ
|
||||
elseif scale == :log2
|
||||
2
|
||||
elseif scale == :log10
|
||||
10
|
||||
end
|
||||
axis = sp[Symbol(letter, :axis)]
|
||||
kw[Symbol(:linthresh, pyletter)] =
|
||||
axis = sp[get_attr_symbol(letter, :axis)]
|
||||
kw[get_attr_symbol(:linthresh, pyletter)] =
|
||||
NaNMath.max(1e-16, py_compute_axis_minval(sp, axis))
|
||||
"symlog"
|
||||
end
|
||||
@@ -893,7 +993,7 @@ end
|
||||
|
||||
function py_set_axis_colors(sp, ax, a::Axis)
|
||||
py_set_spine_color(ax.spines, py_color(a[:foreground_color_border]))
|
||||
axissym = Symbol(a[:letter], :axis)
|
||||
axissym = get_attr_symbol(a[:letter], :axis)
|
||||
if PyPlot.PyCall.hasproperty(ax, axissym)
|
||||
tickcolor =
|
||||
sp[:framestyle] in (:zerolines, :grid) ?
|
||||
@@ -961,6 +1061,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
py_thickness_scale(plt, sp[:titlefontsize]),
|
||||
)
|
||||
getproperty(ax, func)."set_family"(sp[:titlefontfamily])
|
||||
getproperty(ax, func)."set_math_fontfamily"(
|
||||
py_get_matching_math_font(sp[:titlefontfamily]),
|
||||
)
|
||||
getproperty(ax, func)."set_color"(py_color(sp[:titlefontcolor]))
|
||||
# ax[:set_title](sp[:title], loc = loc)
|
||||
end
|
||||
@@ -1053,6 +1156,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
sp[:colorbar_title],
|
||||
size = py_thickness_scale(plt, sp[:colorbar_titlefontsize]),
|
||||
family = sp[:colorbar_titlefontfamily],
|
||||
math_fontfamily = py_get_matching_math_font(sp[:colorbar_titlefontfamily]),
|
||||
color = py_color(sp[:colorbar_titlefontcolor]),
|
||||
)
|
||||
|
||||
@@ -1060,9 +1164,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
cb."formatter".set_powerlimits((-Inf, Inf))
|
||||
cb."update_ticks"()
|
||||
|
||||
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
|
||||
ticks = get_colorbar_ticks(sp)
|
||||
|
||||
if sp[:colorbar] in (:top, :bottom)
|
||||
axis = sp[:xaxis] # colorbar inherits from x axis
|
||||
cbar_axis = cb."ax"."xaxis"
|
||||
@@ -1074,11 +1176,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
py_set_scale(cb.ax, sp, sp[:colorbar_scale], ticks_letter)
|
||||
sp[:colorbar_ticks] == :native ? nothing :
|
||||
py_set_ticks(sp, cb.ax, ticks, ticks_letter, env)
|
||||
py_set_ticks(sp, cb.ax, ticks, ticks_letter)
|
||||
|
||||
for lab in cbar_axis."get_ticklabels"()
|
||||
lab."set_fontsize"(py_thickness_scale(plt, sp[:colorbar_tickfontsize]))
|
||||
lab."set_family"(sp[:colorbar_tickfontfamily])
|
||||
lab."set_math_fontfamily"(
|
||||
py_get_matching_math_font(sp[:colorbar_tickfontfamily]),
|
||||
)
|
||||
lab."set_color"(py_color(sp[:colorbar_tickfontcolor]))
|
||||
end
|
||||
|
||||
@@ -1164,7 +1269,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
|
||||
# axis attributes
|
||||
for letter in (:x, :y, :z)
|
||||
axissym = Symbol(letter, :axis)
|
||||
axissym = get_attr_symbol(letter, :axis)
|
||||
PyPlot.PyCall.hasproperty(ax, axissym) || continue
|
||||
axis = sp[axissym]
|
||||
pyaxis = getproperty(ax, axissym)
|
||||
@@ -1174,7 +1279,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
|
||||
py_set_scale(ax, sp, axis)
|
||||
axis[:ticks] == :native ? nothing : py_set_lims(ax, sp, axis)
|
||||
py_set_lims(ax, sp, axis)
|
||||
if ispolar(sp) && letter == :y
|
||||
ax."set_rlabel_position"(90)
|
||||
end
|
||||
@@ -1188,6 +1293,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
fontProperties = PyPlot.PyCall.PyDict(
|
||||
Dict(
|
||||
"family" => axis[:tickfontfamily],
|
||||
"math_fontfamily" =>
|
||||
py_get_matching_math_font(axis[:tickfontfamily]),
|
||||
"size" => py_thickness_scale(plt, axis[:tickfontsize]),
|
||||
"rotation" => axis[:tickfontrotation],
|
||||
),
|
||||
@@ -1207,10 +1314,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
)
|
||||
end
|
||||
|
||||
# workaround to set mathtext.fontspec per Text element
|
||||
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
|
||||
py_set_ticks(sp, ax, ticks, letter)
|
||||
|
||||
if axis[:ticks] == :native # It is easier to reset than to account for this
|
||||
py_set_lims(ax, sp, axis)
|
||||
pyaxis.set_major_locator(pyticker.AutoLocator())
|
||||
pyaxis.set_major_formatter(pyticker.ScalarFormatter())
|
||||
end
|
||||
|
||||
axis[:ticks] == :native ? nothing : py_set_ticks(sp, ax, ticks, letter, env)
|
||||
# Tick marks
|
||||
intensity = 0.5 # This value corresponds to scaling of other grid elements
|
||||
pyaxis."set_tick_params"(
|
||||
@@ -1226,6 +1337,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
pyaxis."label"."set_fontsize"(py_thickness_scale(plt, axis[:guidefontsize]))
|
||||
pyaxis."label"."set_family"(axis[:guidefontfamily])
|
||||
pyaxis."label"."set_math_fontfamily"(
|
||||
py_get_matching_math_font(axis[:guidefontfamily]),
|
||||
)
|
||||
|
||||
if (RecipesPipeline.is3d(sp))
|
||||
pyaxis."set_rotate_label"(false)
|
||||
@@ -1298,7 +1412,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
if !ispolar(sp)
|
||||
ax.spines[string(dir)].set_visible(false)
|
||||
end
|
||||
kw[dir] = kw[Symbol(:label, dir)] = false
|
||||
kw[dir] = kw[get_attr_symbol(:label, dir)] = false
|
||||
end
|
||||
ax."xaxis"."set_tick_params"(; which = "both", kw...)
|
||||
end
|
||||
@@ -1308,7 +1422,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
if !ispolar(sp)
|
||||
ax.spines[string(dir)].set_visible(false)
|
||||
end
|
||||
kw[dir] = kw[Symbol(:label, dir)] = false
|
||||
kw[dir] = kw[get_attr_symbol(:label, dir)] = false
|
||||
end
|
||||
ax."yaxis"."set_tick_params"(; which = "both", kw...)
|
||||
end
|
||||
@@ -1457,67 +1571,85 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
if should_add_to_legend(series)
|
||||
clims = get_clims(sp, series)
|
||||
# add a line/marker and a label
|
||||
push!(
|
||||
handles,
|
||||
if series[:seriestype] == :shape || series[:fillrange] !== nothing
|
||||
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),
|
||||
),
|
||||
if series[:seriestype] == :shape || series[:fillrange] !== nothing
|
||||
lc = get_linecolor(series, clims)
|
||||
la = get_linealpha(series)
|
||||
ls = get_linestyle(series)
|
||||
fc = get_fillcolor(series, clims)
|
||||
fa = get_fillalpha(series)
|
||||
fs = get_fillstyle(series)
|
||||
has_fs = !isnothing(fs)
|
||||
|
||||
# line (and potentially solid fill)
|
||||
line_handle = pypatches."Patch"(
|
||||
edgecolor = py_color(single_color(lc), la),
|
||||
facecolor = py_color(single_color(fc), has_fs ? 0 : fa),
|
||||
linewidth = py_thickness_scale(
|
||||
plt,
|
||||
clamp(get_linewidth(series), 0, 5),
|
||||
),
|
||||
linestyle = py_linestyle(series[:seriestype], ls),
|
||||
capstyle = "butt",
|
||||
)
|
||||
|
||||
# hatched fill
|
||||
# hatch color/alpha are controlled by edge (not face) color/alpha
|
||||
if has_fs
|
||||
fill_handle = pypatches."Patch"(
|
||||
edgecolor = py_color(single_color(fc), fa),
|
||||
facecolor = py_color(single_color(fc), 0), # don't fill with solid background
|
||||
hatch = py_fillstyle(fs),
|
||||
linewidth = 0, # don't replot shape outline (doesn't affect hatch linewidth)
|
||||
linestyle = py_linestyle(series[:seriestype], ls),
|
||||
capstyle = "butt",
|
||||
)
|
||||
elseif series[:seriestype] in
|
||||
(:path, :straightline, :scatter, :steppre, :stepmid, :steppost)
|
||||
hasline = get_linewidth(series) > 0
|
||||
PyPlot.plt."Line2D"(
|
||||
(0, 1),
|
||||
(0, 0),
|
||||
color = py_color(
|
||||
single_color(get_linecolor(series, clims)),
|
||||
get_linealpha(series),
|
||||
),
|
||||
linewidth = py_thickness_scale(
|
||||
plt,
|
||||
hasline * sp[:legendfontsize] / 8,
|
||||
),
|
||||
linestyle = py_linestyle(:path, get_linestyle(series)),
|
||||
solid_capstyle = "butt",
|
||||
solid_joinstyle = "miter",
|
||||
dash_capstyle = "butt",
|
||||
dash_joinstyle = "miter",
|
||||
marker = py_marker(_cycle(series[:markershape], 1)),
|
||||
markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]),
|
||||
markeredgecolor = py_color(
|
||||
single_color(get_markerstrokecolor(series)),
|
||||
get_markerstrokealpha(series),
|
||||
),
|
||||
markerfacecolor = py_color(
|
||||
single_color(get_markercolor(series, clims)),
|
||||
get_markeralpha(series),
|
||||
),
|
||||
markeredgewidth = py_thickness_scale(
|
||||
plt,
|
||||
0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] /
|
||||
first(series[:markersize]),
|
||||
), # retain the markersize/markerstroke ratio from the markers on the plot
|
||||
)
|
||||
|
||||
# plot two handles on top of each other by passing in a tuple
|
||||
# https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html
|
||||
push!(handles, (line_handle, fill_handle))
|
||||
else
|
||||
series[:serieshandle][1]
|
||||
end,
|
||||
)
|
||||
# plot line handle (which includes solid fill) only
|
||||
push!(handles, line_handle)
|
||||
end
|
||||
elseif series[:seriestype] in
|
||||
(:path, :straightline, :scatter, :steppre, :stepmid, :steppost)
|
||||
hasline = get_linewidth(series) > 0
|
||||
handle = PyPlot.plt."Line2D"(
|
||||
(0, 1),
|
||||
(0, 0),
|
||||
color = py_color(
|
||||
single_color(get_linecolor(series, clims)),
|
||||
get_linealpha(series),
|
||||
),
|
||||
linewidth = py_thickness_scale(
|
||||
plt,
|
||||
hasline * sp[:legendfontsize] / 8,
|
||||
),
|
||||
linestyle = py_linestyle(:path, get_linestyle(series)),
|
||||
solid_capstyle = "butt",
|
||||
solid_joinstyle = "miter",
|
||||
dash_capstyle = "butt",
|
||||
dash_joinstyle = "miter",
|
||||
marker = py_marker(_cycle(series[:markershape], 1)),
|
||||
markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]),
|
||||
markeredgecolor = py_color(
|
||||
single_color(get_markerstrokecolor(series)),
|
||||
get_markerstrokealpha(series),
|
||||
),
|
||||
markerfacecolor = py_color(
|
||||
single_color(get_markercolor(series, clims)),
|
||||
get_markeralpha(series),
|
||||
),
|
||||
markeredgewidth = py_thickness_scale(
|
||||
plt,
|
||||
0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] /
|
||||
first(series[:markersize]),
|
||||
), # retain the markersize/markerstroke ratio from the markers on the plot
|
||||
)
|
||||
push!(handles, handle)
|
||||
else
|
||||
push!(handles, series[:serieshandle][1])
|
||||
end
|
||||
push!(labels, series[:label])
|
||||
end
|
||||
end
|
||||
@@ -1547,6 +1679,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
leg."get_title"(),
|
||||
color = py_color(sp[:legendtitlefontcolor]),
|
||||
family = sp[:legendtitlefontfamily],
|
||||
math_fontfamily = py_get_matching_math_font(sp[:legendtitlefontfamily]),
|
||||
fontsize = py_thickness_scale(plt, sp[:legendtitlefontsize]),
|
||||
)
|
||||
end
|
||||
@@ -1556,6 +1689,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
txt,
|
||||
color = py_color(sp[:legendfontcolor]),
|
||||
family = sp[:legendfontfamily],
|
||||
math_fontfamily = py_get_matching_math_font(sp[:legendtitlefontfamily]),
|
||||
fontsize = py_thickness_scale(plt, sp[:legendfontsize]),
|
||||
)
|
||||
end
|
||||
|
||||
+193
-128
@@ -1,186 +1,251 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
# https://github.com/JuliaPlots/UnicodePlots.jl
|
||||
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
|
||||
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes) = nothing
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------------------
|
||||
const _canvas_map = (
|
||||
ascii = UnicodePlots.AsciiCanvas,
|
||||
block = UnicodePlots.BlockCanvas,
|
||||
braille = UnicodePlots.BrailleCanvas,
|
||||
density = UnicodePlots.DensityCanvas,
|
||||
dot = UnicodePlots.DotCanvas,
|
||||
heatmap = UnicodePlots.HeatmapCanvas,
|
||||
lookup = UnicodePlots.LookupCanvas,
|
||||
)
|
||||
|
||||
function _canvas_map()
|
||||
(
|
||||
braille = UnicodePlots.BrailleCanvas,
|
||||
ascii = UnicodePlots.AsciiCanvas,
|
||||
block = UnicodePlots.BlockCanvas,
|
||||
dot = UnicodePlots.DotCanvas,
|
||||
density = UnicodePlots.DensityCanvas,
|
||||
)
|
||||
end
|
||||
|
||||
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
|
||||
function rebuildUnicodePlot!(plt::Plot, width, height)
|
||||
plt.o = []
|
||||
# do all the magic here... build it all at once,
|
||||
# since we need to know about all the series at the very beginning
|
||||
function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
|
||||
plt.o = UnicodePlots.Plot[]
|
||||
|
||||
for sp in plt.subplots
|
||||
xaxis = sp[:xaxis]
|
||||
yaxis = sp[:yaxis]
|
||||
xlim = axis_limits(sp, :x)
|
||||
ylim = axis_limits(sp, :y)
|
||||
xlim = collect(axis_limits(sp, :x))
|
||||
ylim = collect(axis_limits(sp, :y))
|
||||
|
||||
# make vectors
|
||||
xlim = [xlim[1], xlim[2]]
|
||||
ylim = [ylim[1], ylim[2]]
|
||||
|
||||
# we set x/y to have a single point, since we need to create the plot with some data.
|
||||
# since this point is at the bottom left corner of the plot, it shouldn't actually be shown
|
||||
# we set x/y to have a single point,
|
||||
# since we need to create the plot with some data.
|
||||
# since this point is at the bottom left corner of the plot,
|
||||
# it shouldn't actually be shown
|
||||
x = Float64[xlim[1]]
|
||||
y = Float64[ylim[1]]
|
||||
|
||||
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
|
||||
ct = _canvas_type[]
|
||||
canvas_type = if ct == :auto
|
||||
isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
|
||||
# create a plot window with xlim/ylim set,
|
||||
# but the X/Y vectors are outside the bounds
|
||||
canvas_type = if (ct = _canvas_type[]) == :auto
|
||||
isijulia() ? :ascii : :braille
|
||||
else
|
||||
_canvas_map()[ct]
|
||||
ct
|
||||
end
|
||||
|
||||
# special handling for spy
|
||||
if length(sp.series_list) == 1
|
||||
series = sp.series_list[1]
|
||||
if series[:seriestype] == :spy
|
||||
push!(
|
||||
plt.o,
|
||||
UnicodePlots.spy(
|
||||
series[:z].surf,
|
||||
width = width,
|
||||
height = height,
|
||||
title = sp[:title],
|
||||
canvas = canvas_type,
|
||||
),
|
||||
)
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
# # make it a bar canvas if plotting bar
|
||||
# if any(series -> series[:seriestype] == :bar, series_list(sp))
|
||||
# canvas_type = UnicodePlots.BarplotGraphics
|
||||
# end
|
||||
|
||||
o = UnicodePlots.Plot(
|
||||
x,
|
||||
y,
|
||||
canvas_type;
|
||||
width = width,
|
||||
height = height,
|
||||
kw = (
|
||||
compact = true,
|
||||
title = sp[:title],
|
||||
xlabel = xaxis[:guide],
|
||||
ylabel = yaxis[:guide],
|
||||
xscale = xaxis[:scale],
|
||||
yscale = yaxis[:scale],
|
||||
border = isijulia() ? :ascii : :solid,
|
||||
xlim = xlim,
|
||||
ylim = ylim,
|
||||
border = isijulia() ? :ascii : :solid,
|
||||
)
|
||||
|
||||
# set the axis labels
|
||||
UnicodePlots.xlabel!(o, xaxis[:guide])
|
||||
UnicodePlots.ylabel!(o, yaxis[:guide])
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
o = UnicodePlots.Plot(x, y, _canvas_map[canvas_type]; kw...)
|
||||
for series in series_list(sp)
|
||||
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
|
||||
o = addUnicodeSeries!(sp, o, kw, series, sp[:legend] != :none)
|
||||
end
|
||||
|
||||
# save the object
|
||||
push!(plt.o, o)
|
||||
for ann in sp[:annotations]
|
||||
x, y, val = locate_annotation(sp, ann...)
|
||||
o = UnicodePlots.annotate!(
|
||||
o,
|
||||
x,
|
||||
y,
|
||||
val.str;
|
||||
color = up_color(val.font.color),
|
||||
halign = val.font.halign,
|
||||
valign = val.font.valign,
|
||||
)
|
||||
end
|
||||
|
||||
push!(plt.o, o) # save the object
|
||||
end
|
||||
end
|
||||
|
||||
# add a single series
|
||||
function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim)
|
||||
# get the function, or special handling for step/bar/hist
|
||||
st = plotattributes[:seriestype]
|
||||
if st == :histogram2d
|
||||
UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
|
||||
return
|
||||
end
|
||||
up_color(col::UnicodePlots.UserColorType) = col
|
||||
up_color(col::RGBA) =
|
||||
(c = convert(ARGB32, col); map(Int, (red(c).i, green(c).i, blue(c).i)))
|
||||
up_color(col) = :auto
|
||||
|
||||
if st in (:path, :straightline)
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif st == :scatter || plotattributes[:markershape] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
# elseif st == :bar
|
||||
# func = UnicodePlots.barplot!
|
||||
elseif st == :shape
|
||||
func = UnicodePlots.lineplot!
|
||||
else
|
||||
error("Linestyle $st not supported by UnicodePlots")
|
||||
end
|
||||
# add a single series
|
||||
function addUnicodeSeries!(
|
||||
sp::Subplot{UnicodePlotsBackend},
|
||||
up::UnicodePlots.Plot,
|
||||
kw,
|
||||
series,
|
||||
addlegend::Bool,
|
||||
)
|
||||
st = series[:seriestype]
|
||||
|
||||
# get the series data and label
|
||||
x, y = if st == :straightline
|
||||
straightline_data(plotattributes)
|
||||
straightline_data(series)
|
||||
elseif st == :shape
|
||||
shape_data(plotattributes)
|
||||
shape_data(series)
|
||||
else
|
||||
[collect(float(plotattributes[s])) for s in (:x, :y)]
|
||||
float(series[:x]), float(series[:y])
|
||||
end
|
||||
label = addlegend ? plotattributes[:label] : ""
|
||||
|
||||
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
|
||||
color =
|
||||
plotattributes[:linecolor] in UnicodePlots.color_cycle ?
|
||||
plotattributes[:linecolor] : :auto
|
||||
# special handling (src/interface)
|
||||
if st == :histogram2d
|
||||
kw[:xlim][:] .= kw[:ylim][:] .= 0
|
||||
return UnicodePlots.densityplot(x, y; kw...)
|
||||
elseif st == :heatmap
|
||||
rng = range(0, 1, length = length(UnicodePlots.COLOR_MAP_DATA[:viridis]))
|
||||
cmap = [(red(c), green(c), blue(c)) for c in get(get_colorgradient(series), rng)]
|
||||
return UnicodePlots.heatmap(
|
||||
series[:z].surf;
|
||||
zlabel = sp[:colorbar_title],
|
||||
colormap = cmap,
|
||||
kw...,
|
||||
)
|
||||
elseif st == :spy
|
||||
return UnicodePlots.spy(series[:z].surf; kw...)
|
||||
end
|
||||
|
||||
# add the series
|
||||
x, y = RecipesPipeline.unzip(
|
||||
collect(Base.Iterators.filter(xy -> isfinite(xy[1]) && isfinite(xy[2]), zip(x, y))),
|
||||
)
|
||||
func(o, x, y; color = color, name = label)
|
||||
series_kw = (;)
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
if st in (:path, :straightline, :shape)
|
||||
func = UnicodePlots.lineplot!
|
||||
elseif st == :scatter || series[:markershape] != :none
|
||||
func = UnicodePlots.scatterplot!
|
||||
series_kw = (; marker = series[:markershape])
|
||||
else
|
||||
error("Series type $st not supported by UnicodePlots")
|
||||
end
|
||||
|
||||
label = addlegend ? series[:label] : ""
|
||||
|
||||
for (n, segment) in enumerate(series_segments(series, st; check = true))
|
||||
i, rng = segment.attr_index, segment.range
|
||||
lc = get_linecolor(series, i)
|
||||
up = func(
|
||||
up,
|
||||
x[rng],
|
||||
y[rng];
|
||||
color = up_color(lc),
|
||||
name = n == 1 ? label : "",
|
||||
series_kw...,
|
||||
)
|
||||
end
|
||||
|
||||
for (xi, yi, str, fnt) in EachAnn(series[:series_annotations], x, y)
|
||||
up = UnicodePlots.annotate!(
|
||||
up,
|
||||
xi,
|
||||
yi,
|
||||
str;
|
||||
color = up_color(fnt.color),
|
||||
halign = fnt.halign,
|
||||
valign = fnt.valign,
|
||||
)
|
||||
end
|
||||
|
||||
return up
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
# ------------------------------------------------------------------------------------------
|
||||
|
||||
# since this is such a hack, it's only callable using `png`... should error during normal `show`
|
||||
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
|
||||
# since this is such a hack, it's only callable using `png`...
|
||||
# should error during normal `show`
|
||||
function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
|
||||
fn = addExtension(fn, "png")
|
||||
|
||||
# make some whitespace and show the plot
|
||||
println("\n\n\n\n\n\n")
|
||||
gui(plt)
|
||||
|
||||
# @osx_only begin
|
||||
@static if Sys.isapple()
|
||||
# BEGIN HACK
|
||||
|
||||
# wait while the plot gets drawn
|
||||
# make some whitespace and show the plot
|
||||
println("\n\n\n\n\n\n")
|
||||
gui(plt)
|
||||
sleep(0.5)
|
||||
|
||||
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
|
||||
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
|
||||
# use osx screen capture when my terminal is maximized
|
||||
# and cursor starts at the bottom (I know, right?)
|
||||
run(`screencapture -R50,600,700,420 $fn`)
|
||||
|
||||
# END HACK (phew)
|
||||
return
|
||||
elseif Sys.islinux()
|
||||
run(`clear`)
|
||||
gui(plt)
|
||||
run(`import -window $(ENV["WINDOWID"]) $fn`)
|
||||
return
|
||||
end
|
||||
|
||||
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
|
||||
error(
|
||||
"Can only savepng on MacOS or Linux with UnicodePlots " *
|
||||
"(though even then I wouldn't do it)",
|
||||
)
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# we don't do very much for subplots... just stack them vertically
|
||||
|
||||
function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
|
||||
w, h = plt[:size]
|
||||
plt.attr[:color_palette] = [RGB(0, 0, 0)]
|
||||
rebuildUnicodePlot!(plt, div(w, 10), div(h, 20))
|
||||
end
|
||||
# ------------------------------------------------------------------------------------------
|
||||
Base.show(plt::Plot{UnicodePlotsBackend}) = show(stdout, plt)
|
||||
Base.show(io::IO, plt::Plot{UnicodePlotsBackend}) = _show(io, MIME("text/plain"), plt)
|
||||
|
||||
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
|
||||
unicodeplots_rebuild(plt)
|
||||
foreach(x -> show(io, x), plt.o)
|
||||
nr, nc = size(plt.layout)
|
||||
lines_colored = Array{Union{Nothing,Vector{String}}}(undef, nr, nc)
|
||||
lines_uncolored = copy(lines_colored)
|
||||
l_max = zeros(Int, nr)
|
||||
w_max = zeros(Int, nc)
|
||||
buf = IOBuffer()
|
||||
cbuf = IOContext(buf, :color => true)
|
||||
re_col = r"\x1B\[[0-9;]*[a-zA-Z]"
|
||||
sps = 0
|
||||
for r in 1:nr
|
||||
lmax = 0
|
||||
for c in 1:nc
|
||||
l = plt.layout[r, c]
|
||||
if l isa GridLayout && size(l) != (1, 1)
|
||||
@error "UnicodePlots: complex nested layout is currently unsupported !"
|
||||
else
|
||||
if get(l.attr, :blank, false)
|
||||
lines_colored[r, c] = lines_uncolored[r, c] = nothing
|
||||
else
|
||||
sp = plt.o[sps += 1]
|
||||
show(cbuf, sp)
|
||||
colored = String(take!(buf))
|
||||
uncolored = replace(colored, re_col => "")
|
||||
lines_colored[r, c] = lc = split(colored, "\n")
|
||||
lines_uncolored[r, c] = lu = split(uncolored, "\n")
|
||||
lmax = max(length(lc), lmax)
|
||||
w_max[c] = max(maximum(length.(lu)), w_max[c])
|
||||
end
|
||||
end
|
||||
end
|
||||
l_max[r] = lmax
|
||||
end
|
||||
empty = String[' '^w for w in w_max]
|
||||
for r in 1:nr
|
||||
for n in 1:l_max[r]
|
||||
for c in 1:nc
|
||||
pre = c == 1 ? '\0' : ' '
|
||||
lc = lines_colored[r, c]
|
||||
if lc === nothing || length(lc) < n
|
||||
print(io, pre, empty[c])
|
||||
else
|
||||
lu = lines_uncolored[r, c]
|
||||
print(io, pre, lc[n], ' '^(w_max[c] - length(lu[n])))
|
||||
end
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
r < nr && println(io)
|
||||
end
|
||||
nothing
|
||||
end
|
||||
|
||||
function _display(plt::Plot{UnicodePlotsBackend})
|
||||
unicodeplots_rebuild(plt)
|
||||
map(show, plt.o)
|
||||
map(display, plt.o)
|
||||
nothing
|
||||
end
|
||||
|
||||
+16
-16
@@ -5,33 +5,32 @@ process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema
|
||||
# don't specialize on ::Function otherwise python functions won't work
|
||||
process_clims(f) = f
|
||||
|
||||
function get_clims(sp::Subplot, op = process_clims(sp[:clims]))
|
||||
get_clims(sp::Subplot)::Tuple{Float64,Float64} = sp[:crange]
|
||||
get_clims(series::Series)::Tuple{Float64,Float64} = series[:crange]
|
||||
|
||||
get_clims(sp::Subplot, series::Series)::Tuple{Float64,Float64} =
|
||||
series[:colorbar_entry] ? sp[:crange] : series[:crange]
|
||||
|
||||
function update_clims(sp::Subplot, op = process_clims(sp[:clims]))::Tuple{Float64,Float64}
|
||||
zmin, zmax = Inf, -Inf
|
||||
for series in series_list(sp)
|
||||
if series[:colorbar_entry]
|
||||
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
|
||||
zmin, zmax = _update_clims(zmin, zmax, update_clims(series, op)...)
|
||||
else
|
||||
update_clims(series, op)
|
||||
end
|
||||
end
|
||||
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
end
|
||||
|
||||
function get_clims(sp::Subplot, series::Series, op = process_clims(sp[:clims]))
|
||||
zmin, zmax = if series[:colorbar_entry]
|
||||
get_clims(sp, op)
|
||||
else
|
||||
get_clims(series, op)
|
||||
end
|
||||
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
return sp[:crange] = zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
end
|
||||
|
||||
"""
|
||||
get_clims(::Series, op=Plots.ignorenan_extrema)
|
||||
update_clims(::Series, op=Plots.ignorenan_extrema)
|
||||
|
||||
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
|
||||
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
|
||||
values of the input.
|
||||
values of the input. The value is stored as a series property, which is retrieved by `get_clims`.
|
||||
"""
|
||||
function get_clims(series::Series, op = ignorenan_extrema)
|
||||
function update_clims(series::Series, op = ignorenan_extrema)::Tuple{Float64,Float64}
|
||||
zmin, zmax = Inf, -Inf
|
||||
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
|
||||
for vals in (
|
||||
@@ -46,7 +45,7 @@ function get_clims(series::Series, op = ignorenan_extrema)
|
||||
zmin, zmax = _update_clims(zmin, zmax, op(vals)...)
|
||||
end
|
||||
end
|
||||
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
return series[:crange] = zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
|
||||
end
|
||||
|
||||
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
|
||||
@@ -94,4 +93,5 @@ end
|
||||
|
||||
function _update_subplot_colorbars(sp::Subplot)
|
||||
# Dynamic callback from the pipeline if needed
|
||||
update_clims(sp)
|
||||
end
|
||||
|
||||
+3
-3
@@ -321,7 +321,7 @@ function scalefontsizes(factor::Number)
|
||||
|
||||
for letter in (:x, :y, :z)
|
||||
for k in keys(_initial_ax_fontsizes)
|
||||
scalefontsize(Symbol(letter, k), factor)
|
||||
scalefontsize(get_attr_symbol(letter, k), factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -343,9 +343,9 @@ function scalefontsizes()
|
||||
for letter in (:x, :y, :z)
|
||||
for k in keys(_initial_ax_fontsizes)
|
||||
if k in keys(_initial_fontsizes)
|
||||
f = default(Symbol(letter, k))
|
||||
f = default(get_attr_symbol(letter, k))
|
||||
factor = f / _initial_fontsizes[k]
|
||||
scalefontsize(Symbol(letter, k), 1.0 / factor)
|
||||
scalefontsize(get_attr_symbol(letter, k), 1.0 / factor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+39
-14
@@ -125,7 +125,8 @@ const _examples = PlotExample[
|
||||
:(
|
||||
begin
|
||||
import FileIO
|
||||
path = download(
|
||||
import Downloads
|
||||
path = Downloads.download(
|
||||
"http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png",
|
||||
)
|
||||
img = FileIO.load(path)
|
||||
@@ -961,8 +962,10 @@ const _examples = PlotExample[
|
||||
"""
|
||||
Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically.
|
||||
You can also specify the connections using the connections keyword.
|
||||
The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle,
|
||||
such that elements at the same position of these vectors form a triangle.
|
||||
The connections can be specified in two ways: Either as a tuple of vectors where each vector
|
||||
contains the 0-based indices of one point of a triangle, such that elements at the same
|
||||
position of these vectors form a triangle. Or as a vector of NTuple{3,Ints} where each element
|
||||
contains the 1-based indices of the three points of a triangle.
|
||||
""",
|
||||
[
|
||||
:(
|
||||
@@ -978,13 +981,14 @@ const _examples = PlotExample[
|
||||
i = [0, 0, 0, 1]
|
||||
j = [1, 2, 3, 2]
|
||||
k = [2, 3, 1, 3]
|
||||
# Or: cns = [(1, 2, 3), (1, 3, 4), (1, 4, 2), (2, 3, 4)] (1-based indexing)
|
||||
|
||||
# the four triangles gives above give a tetrahedron
|
||||
mesh3d(
|
||||
x,
|
||||
y,
|
||||
z;
|
||||
connections = (i, j, k),
|
||||
connections = (i, j, k), # connections = cns
|
||||
title = "triangles",
|
||||
xlabel = "x",
|
||||
ylabel = "y",
|
||||
@@ -1234,21 +1238,42 @@ const _examples = PlotExample[
|
||||
_animation_examples = [2, 31]
|
||||
_backend_skips = Dict(
|
||||
:gr => [25, 30],
|
||||
:pyplot => [2, 25, 30, 31, 47, 49, 55],
|
||||
:pyplot => [2, 25, 30, 31, 49, 55],
|
||||
:plotlyjs => [2, 21, 24, 25, 30, 31, 49, 51, 55],
|
||||
:plotly => [2, 21, 24, 25, 30, 31, 49, 50, 51, 55],
|
||||
:pgfplotsx => [
|
||||
2, # animation
|
||||
6, # images
|
||||
16, # pgfplots thinks the upper panel is too small
|
||||
30, # @df
|
||||
31, # animation
|
||||
32, # spy
|
||||
49, # polar heatmap
|
||||
51, # image with custom axes
|
||||
2, # animation
|
||||
6, # images
|
||||
16, # pgfplots thinks the upper panel is too small
|
||||
30, # @df
|
||||
31, # animation
|
||||
32, # spy
|
||||
49, # polar heatmap
|
||||
51, # image with custom axes
|
||||
],
|
||||
:inspectdr => [4, 6, 10, 22, 24, 28, 30, 38, 43, 45, 47, 48, 49, 50, 51, 55],
|
||||
:unicodeplots => [6, 10, 22, 24, 28, 38, 43, 45, 47, 49, 50, 51, 55],
|
||||
:unicodeplots => [
|
||||
5, # limits issue
|
||||
6, # embedded images unsupported
|
||||
16, # nested layout unsupported
|
||||
21, # custom markers unsupported
|
||||
22, # contours unsupported
|
||||
24, # 3D unsupported
|
||||
26, # nested layout unsupported
|
||||
27, # polar plots unsupported
|
||||
29, # nested layout unsupported
|
||||
33, # grid lines unsupported
|
||||
34, # framestyle unsupported
|
||||
37, # ribbons / filled unsupported
|
||||
43, # heatmap with DateTime
|
||||
45, # error bars
|
||||
47, # mesh3D unsupported
|
||||
49, # polar heatmap
|
||||
50, # 3D surface unsupported
|
||||
51, # embedded images unsupported
|
||||
52, # 3D quiver unsupported
|
||||
55, # 3D unsupported
|
||||
],
|
||||
:gaston => [
|
||||
2, # animations
|
||||
31, # animations
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ function __init__()
|
||||
global plotly_local_file_path[] =
|
||||
joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
|
||||
if !isfile(plotly_local_file_path[])
|
||||
download(
|
||||
Downloads.download(
|
||||
"https://cdn.plot.ly/$(_plotly_min_js_filename)",
|
||||
plotly_local_file_path[],
|
||||
)
|
||||
|
||||
+3
-2
@@ -250,12 +250,12 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
||||
v = v[series_idx(kw_list, kw)]
|
||||
end
|
||||
for letter in (:x, :y, :z)
|
||||
attr[Symbol(letter, k)] = v
|
||||
attr[get_attr_symbol(letter, k)] = v
|
||||
end
|
||||
end
|
||||
for k in (:scale,), letter in (:x, :y, :z)
|
||||
# Series recipes may need access to this information
|
||||
lk = Symbol(letter, k)
|
||||
lk = get_attr_symbol(letter, k)
|
||||
if haskey(attr, lk)
|
||||
kw[lk] = attr[lk]
|
||||
end
|
||||
@@ -416,4 +416,5 @@ function _add_the_series(plt, sp, plotattributes)
|
||||
push!(plt.series_list, series)
|
||||
push!(sp.series_list, series)
|
||||
_series_added(plt, series)
|
||||
_update_subplot_colorbars(sp)
|
||||
end
|
||||
|
||||
@@ -7,10 +7,9 @@ ismultiversion = false
|
||||
@static if !should_precompile
|
||||
# nothing
|
||||
elseif !ismultios && !ismultiversion
|
||||
@static if isfile(joinpath(
|
||||
@__DIR__,
|
||||
"../deps/SnoopCompile/precompile/precompile_Plots.jl",
|
||||
))
|
||||
@static if isfile(
|
||||
joinpath(@__DIR__, "../deps/SnoopCompile/precompile/precompile_Plots.jl"),
|
||||
)
|
||||
include("../deps/SnoopCompile/precompile/precompile_Plots.jl")
|
||||
_precompile_()
|
||||
end
|
||||
|
||||
+8
-2
@@ -47,7 +47,7 @@ num_series(x::AMat) = size(x, 2)
|
||||
num_series(x) = 1
|
||||
|
||||
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} =
|
||||
throw(MethodError(T, "Unmatched plot recipe: $T"))
|
||||
nothing
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -1042,7 +1042,13 @@ export lens!
|
||||
series_plotindex := backup[:series_plotindex]
|
||||
seriestype := :path
|
||||
primary := false
|
||||
linecolor := :lightgray
|
||||
linecolor := get(backup, :linecolor, :lightgray)
|
||||
if haskey(backup, :linestyle)
|
||||
linestyle := backup[:linestyle]
|
||||
end
|
||||
if haskey(backup, :linewidth)
|
||||
linewidth := backup[:linewidth]
|
||||
end
|
||||
bbx_mag = (x1 + x2) / 2
|
||||
bby_mag = (y1 + y2) / 2
|
||||
xi_lens, yi_lens =
|
||||
|
||||
+40
-13
@@ -205,14 +205,15 @@ maketuple(x::Tuple{T,S}) where {T,S} = x
|
||||
for i in 2:4
|
||||
@eval begin
|
||||
RecipesPipeline.unzip(
|
||||
v::Union{AVec{<:Tuple{Vararg{T,$i} where T}},AVec{<:GeometryBasics.Point{$i}}},
|
||||
v::Union{AVec{<:NTuple{$i,T} where {T}},AVec{<:GeometryBasics.Point{$i}}},
|
||||
) = $(Expr(:tuple, (:([t[$j] for t in v]) for j in 1:i)...))
|
||||
end
|
||||
end
|
||||
|
||||
RecipesPipeline.unzip(
|
||||
::Union{AVec{<:GeometryBasics.Point{N}},AVec{<:Tuple{Vararg{T,N} where T}}},
|
||||
::Union{AVec{<:GeometryBasics.Point{N}},AVec{<:NTuple{N,T} where {T}}},
|
||||
) where {N} = error("$N-dimensional unzip not implemented.")
|
||||
|
||||
RecipesPipeline.unzip(::Union{AVec{<:GeometryBasics.Point},AVec{<:Tuple}}) =
|
||||
error("Can't unzip points of different dimensions.")
|
||||
|
||||
@@ -538,6 +539,7 @@ get_gradient(cp::ColorPalette) = cgrad(cp, categorical = true)
|
||||
|
||||
get_linewidth(series, i::Int = 1) = _cycle(series[:linewidth], i)
|
||||
get_linestyle(series, i::Int = 1) = _cycle(series[:linestyle], i)
|
||||
get_fillstyle(series, i::Int = 1) = _cycle(series[:fillstyle], i)
|
||||
|
||||
function get_markerstrokecolor(series, i::Int = 1)
|
||||
msc = series[:markerstrokecolor]
|
||||
@@ -556,6 +558,7 @@ const _segmenting_vector_attributes = (
|
||||
:linestyle,
|
||||
:fillcolor,
|
||||
:fillalpha,
|
||||
:fillstyle,
|
||||
:markercolor,
|
||||
:markeralpha,
|
||||
:markersize,
|
||||
@@ -814,7 +817,7 @@ end
|
||||
function extend_series_data!(series::Series, v, letter)
|
||||
copy_series!(series, letter)
|
||||
d = extend_by_data!(series[letter], v)
|
||||
expand_extrema!(series[:subplot][Symbol(letter, :axis)], d)
|
||||
expand_extrema!(series[:subplot][get_attr_symbol(letter, :axis)], d)
|
||||
return d
|
||||
end
|
||||
|
||||
@@ -1178,16 +1181,10 @@ end
|
||||
_document_argument(S::AbstractString) =
|
||||
_fmt_paragraph("`$S`: " * _arg_desc[Symbol(S)], leadingspaces = 6 + length(S))
|
||||
|
||||
function mesh3d_triangles(x, y, z, cns)
|
||||
if typeof(cns) <: Tuple{Array,Array,Array}
|
||||
ci, cj, ck = cns
|
||||
if !(length(ci) == length(cj) == length(ck))
|
||||
throw(
|
||||
ArgumentError("Argument connections must consist of equally sized arrays."),
|
||||
)
|
||||
end
|
||||
else
|
||||
throw(ArgumentError("Argument connections has to be a tuple of three arrays."))
|
||||
function mesh3d_triangles(x, y, z, cns::Tuple{Array,Array,Array})
|
||||
ci, cj, ck = cns
|
||||
if !(length(ci) == length(cj) == length(ck))
|
||||
throw(ArgumentError("Argument connections must consist of equally sized arrays."))
|
||||
end
|
||||
X = zeros(eltype(x), 4length(ci))
|
||||
Y = zeros(eltype(y), 4length(cj))
|
||||
@@ -1212,3 +1209,33 @@ function mesh3d_triangles(x, y, z, cns)
|
||||
end
|
||||
return X, Y, Z
|
||||
end
|
||||
function mesh3d_triangles(x, y, z, cns::AbstractVector{NTuple{3,Int}})
|
||||
X = zeros(eltype(x), 4length(cns))
|
||||
Y = zeros(eltype(y), 4length(cns))
|
||||
Z = zeros(eltype(z), 4length(cns))
|
||||
@inbounds for I in 1:length(cns)
|
||||
i = cns[I][1] # connections are 1-based
|
||||
j = cns[I][2]
|
||||
k = cns[I][3]
|
||||
m = 4(I - 1) + 1
|
||||
n = m + 1
|
||||
o = m + 2
|
||||
p = m + 3
|
||||
X[m] = X[p] = x[i]
|
||||
Y[m] = Y[p] = y[i]
|
||||
Z[m] = Z[p] = z[i]
|
||||
X[n] = x[j]
|
||||
Y[n] = y[j]
|
||||
Z[n] = z[j]
|
||||
X[o] = x[k]
|
||||
Y[o] = y[k]
|
||||
Z[o] = z[k]
|
||||
end
|
||||
return X, Y, Z
|
||||
end
|
||||
|
||||
# cache joined symbols so they can be looked up instead of constructed each time
|
||||
const _attrsymbolcache = Dict{Symbol,Dict{Symbol,Symbol}}()
|
||||
|
||||
get_attr_symbol(letter::Symbol, keyword::String) = get_attr_symbol(letter, Symbol(keyword))
|
||||
get_attr_symbol(letter::Symbol, keyword::Symbol) = _attrsymbolcache[letter][keyword]
|
||||
|
||||
+90
-78
@@ -1,17 +1,26 @@
|
||||
using Plots: guidefont, series_annotations, PLOTS_SEED
|
||||
import ImageMagick
|
||||
|
||||
using VisualRegressionTests
|
||||
using Plots
|
||||
using Random
|
||||
using StableRNGs
|
||||
using Test
|
||||
using TestImages
|
||||
using FileIO
|
||||
using Gtk
|
||||
using LibGit2
|
||||
import GeometryBasics
|
||||
using Dates
|
||||
using RecipesBase
|
||||
using StableRNGs
|
||||
using TestImages
|
||||
using LibGit2
|
||||
using Random
|
||||
using FileIO
|
||||
using Plots
|
||||
using Dates
|
||||
using JSON
|
||||
using Test
|
||||
using Gtk
|
||||
|
||||
import GeometryBasics
|
||||
import ImageMagick
|
||||
|
||||
@testset "Infrastructure" begin
|
||||
@test_nowarn JSON.Parser.parse(
|
||||
String(read(joinpath(dirname(pathof(Plots)), "..", ".zenodo.json"))),
|
||||
)
|
||||
end
|
||||
|
||||
@testset "Plotly standalone" begin
|
||||
@test_nowarn Plots._init_ijulia_plotting()
|
||||
@@ -26,11 +35,12 @@ using RecipesBase
|
||||
end
|
||||
Plots.plotly_local_file_path[] = nothing
|
||||
Plots.use_local_dependencies[] = temp
|
||||
end # testset
|
||||
end
|
||||
|
||||
include("test_defaults.jl")
|
||||
include("test_pipeline.jl")
|
||||
include("test_axes.jl")
|
||||
include("test_contours.jl")
|
||||
include("test_axis_letter.jl")
|
||||
include("test_components.jl")
|
||||
include("test_shorthands.jl")
|
||||
@@ -38,6 +48,7 @@ include("integration_dates.jl")
|
||||
include("test_recipes.jl")
|
||||
include("test_hdf5plots.jl")
|
||||
include("test_pgfplotsx.jl")
|
||||
include("test_plotly.jl")
|
||||
|
||||
reference_dir(args...) =
|
||||
joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
|
||||
@@ -46,7 +57,6 @@ function reference_file(backend, i, version)
|
||||
refdir = reference_dir("Plots", string(backend))
|
||||
fn = "ref$i.png"
|
||||
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
|
||||
|
||||
reffn = joinpath(refdir, string(version), fn)
|
||||
for v in versions
|
||||
tmpfn = joinpath(refdir, string(v), fn)
|
||||
@@ -55,7 +65,6 @@ function reference_file(backend, i, version)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return reffn
|
||||
end
|
||||
|
||||
@@ -70,9 +79,10 @@ if !isdir(reference_dir())
|
||||
end
|
||||
|
||||
include("imgcomp.jl")
|
||||
# don't actually show the plots
|
||||
Random.seed!(PLOTS_SEED)
|
||||
default(show = false, reuse = true)
|
||||
|
||||
default(show = false, reuse = true) # don't actually show the plots
|
||||
|
||||
is_ci() = get(ENV, "CI", "false") == "true"
|
||||
const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" : "1e-5"))
|
||||
|
||||
@@ -97,66 +107,8 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4"
|
||||
# image_comparison_facts(:pgfplotsx, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
|
||||
# end
|
||||
|
||||
# 10 Histogram2D
|
||||
|
||||
##
|
||||
|
||||
@testset "Backends" begin
|
||||
@testset "GR" begin
|
||||
ENV["PLOTS_TEST"] = "true"
|
||||
ENV["GKSwstype"] = "100"
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
@static if haskey(ENV, "APPVEYOR")
|
||||
@info "Skipping GR image comparison tests on AppVeyor"
|
||||
else
|
||||
image_comparison_facts(
|
||||
:gr,
|
||||
tol = PLOTS_IMG_TOL,
|
||||
skip = Plots._backend_skips[:gr],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
# lets just make sure it runs without error
|
||||
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
|
||||
p = plot([1, 2], [3, 4])
|
||||
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
|
||||
hline!(p, [3.1])
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
|
||||
hline!(p, [3.1])
|
||||
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
|
||||
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
|
||||
hline!(p, [3.1])
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test isa(display(p), Nothing) == true
|
||||
end
|
||||
|
||||
@testset "PlotlyJS" begin
|
||||
@test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
@test backend() == Plots.PlotlyJSBackend()
|
||||
|
||||
p = plot(rand(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
@test_broken isa(display(p), Nothing) == true
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Axes" begin
|
||||
p = plot()
|
||||
axis = p.subplots[1][:xaxis]
|
||||
@@ -172,10 +124,12 @@ end
|
||||
end
|
||||
|
||||
@testset "NoFail" begin
|
||||
#ensure backend with tested display
|
||||
# ensure backend with tested display
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
dsp = TextDisplay(IOContext(IOBuffer(), :color => true))
|
||||
|
||||
@testset "Plot" begin
|
||||
plots = [
|
||||
histogram([1, 0, 0, 0, 0, 0]),
|
||||
@@ -188,15 +142,15 @@ end
|
||||
plot(["a" "b"; missing "d"], [1 2; 3 4]),
|
||||
]
|
||||
for plt in plots
|
||||
display(plt)
|
||||
display(dsp, plt)
|
||||
end
|
||||
@test_nowarn plot(x -> x^2, 0, 2)
|
||||
end
|
||||
|
||||
@testset "Bar" begin
|
||||
p = bar([3, 2, 1], [1, 2, 3])
|
||||
@test isa(p, Plots.Plot)
|
||||
@test isa(display(p), Nothing) == true
|
||||
@test p isa Plots.Plot
|
||||
@test display(dsp, p) isa Nothing
|
||||
end
|
||||
end
|
||||
|
||||
@@ -246,3 +200,61 @@ end
|
||||
Plots.process_clims(missing) ==
|
||||
Plots.process_clims(:auto)
|
||||
end
|
||||
|
||||
@testset "Backends" begin
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@test backend() == Plots.UnicodePlotsBackend()
|
||||
|
||||
io = IOContext(IOBuffer(), :color => true)
|
||||
|
||||
# lets just make sure it runs without error
|
||||
p = plot(rand(10))
|
||||
@test p isa Plots.Plot
|
||||
@test show(io, p) isa Nothing
|
||||
p = bar(randn(10))
|
||||
@test p isa Plots.Plot
|
||||
@test show(io, p) isa Nothing
|
||||
p = plot([1, 2], [3, 4])
|
||||
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
|
||||
hline!(p, [3.1])
|
||||
@test p isa Plots.Plot
|
||||
@test show(io, p) isa Nothing
|
||||
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
|
||||
hline!(p, [3.1])
|
||||
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
|
||||
@test p isa Plots.Plot
|
||||
@test show(io, p) isa Nothing
|
||||
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
|
||||
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
|
||||
hline!(p, [3.1])
|
||||
@test p isa Plots.Plot
|
||||
@test show(io, p) isa Nothing
|
||||
end
|
||||
|
||||
@testset "PlotlyJS" begin
|
||||
@test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
@test backend() == Plots.PlotlyJSBackend()
|
||||
|
||||
p = plot(rand(10))
|
||||
@test p isa Plots.Plot
|
||||
@test_broken display(p) isa Nothing
|
||||
end
|
||||
|
||||
@testset "GR" begin
|
||||
ENV["PLOTS_TEST"] = "true"
|
||||
ENV["GKSwstype"] = "100"
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
@static if haskey(ENV, "APPVEYOR")
|
||||
@info "Skipping GR image comparison tests on AppVeyor"
|
||||
else
|
||||
image_comparison_facts(
|
||||
:gr,
|
||||
tol = PLOTS_IMG_TOL,
|
||||
skip = Plots._backend_skips[:gr],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,3 +63,57 @@ end
|
||||
@test twpl[:top_margin] == 2Plots.cm
|
||||
@test twpl[:bottom_margin] == 2Plots.cm
|
||||
end
|
||||
|
||||
@testset "axis-aliases" begin
|
||||
p = plot(1:2, xl = "x label")
|
||||
@test p[1][:xaxis][:guide] === "x label"
|
||||
p = plot(1:2, xrange = (0, 3))
|
||||
@test xlims(p) === (0, 3)
|
||||
p = plot(1:2, xtick = [1.25, 1.5, 1.75])
|
||||
@test p[1][:xaxis][:ticks] == [1.25, 1.5, 1.75]
|
||||
p = plot(1:2, xlabelfontsize = 4)
|
||||
@test p[1][:xaxis][:guidefontsize] == 4
|
||||
p = plot(1:2, xgα = 0.07)
|
||||
@test p[1][:xaxis][:gridalpha] ≈ 0.07
|
||||
p = plot(1:2, xgridls = :dashdot)
|
||||
@test p[1][:xaxis][:gridstyle] === :dashdot
|
||||
p = plot(1:2, xgridcolor = :red)
|
||||
@test p[1][:xaxis][:foreground_color_grid] === RGBA{Float64}(1.0, 0.0, 0.0, 1.0)
|
||||
p = plot(1:2, xminorgridcolor = :red)
|
||||
@test p[1][:xaxis][:foreground_color_minor_grid] === RGBA{Float64}(1.0, 0.0, 0.0, 1.0)
|
||||
p = plot(1:2, xgrid_lw = 0.01)
|
||||
@test p[1][:xaxis][:gridlinewidth] ≈ 0.01
|
||||
p = plot(1:2, xminorgrid_lw = 0.01)
|
||||
@test p[1][:xaxis][:minorgridlinewidth] ≈ 0.01
|
||||
p = plot(1:2, xtickor = :out)
|
||||
@test p[1][:xaxis][:tick_direction] === :out
|
||||
end
|
||||
|
||||
@testset "aliases" begin
|
||||
compare(p::Plots.Plot, s::Symbol, val, op) =
|
||||
op(p[1][:xaxis][s], val) && op(p[1][:yaxis][s], val) && op(p[1][:zaxis][s], val)
|
||||
p = plot(1:2, guide = "all labels")
|
||||
@test compare(p, :guide, "all labels", ===)
|
||||
p = plot(1:2, label = "test")
|
||||
@test compare(p, :guide, "", ===)
|
||||
p = plot(1:2, lim = (0, 3))
|
||||
@test xlims(p) === ylims(p) === zlims(p) === (0, 3)
|
||||
p = plot(1:2, tick = [1.25, 1.5, 1.75])
|
||||
@test compare(p, :ticks, [1.25, 1.5, 1.75], ==)
|
||||
p = plot(1:2, labelfontsize = 4)
|
||||
@test compare(p, :guidefontsize, 4, ==)
|
||||
p = plot(1:2, gα = 0.07)
|
||||
@test compare(p, :gridalpha, 0.07, ≈)
|
||||
p = plot(1:2, gridls = :dashdot)
|
||||
@test compare(p, :gridstyle, :dashdot, ===)
|
||||
p = plot(1:2, gridcolor = :red)
|
||||
@test compare(p, :foreground_color_grid, RGBA{Float64}(1.0, 0.0, 0.0, 1.0), ===)
|
||||
p = plot(1:2, minorgridcolor = :red)
|
||||
@test compare(p, :foreground_color_minor_grid, RGBA{Float64}(1.0, 0.0, 0.0, 1.0), ===)
|
||||
p = plot(1:2, grid_lw = 0.01)
|
||||
@test compare(p, :gridlinewidth, 0.01, ≈)
|
||||
p = plot(1:2, minorgrid_lw = 0.01)
|
||||
@test compare(p, :minorgridlinewidth, 0.01, ≈)
|
||||
p = plot(1:2, tickor = :out)
|
||||
@test compare(p, :tick_direction, :out, ===)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
using Plots, Test
|
||||
import RecipesPipeline
|
||||
|
||||
@testset "Contours" begin
|
||||
@testset "check_contour_levels" begin
|
||||
@test Plots.check_contour_levels(2) === nothing
|
||||
@test Plots.check_contour_levels(-1.0:0.2:10.0) === nothing
|
||||
@test Plots.check_contour_levels([-100, -2, -1, 0, 1, 2, 100]) === nothing
|
||||
@test_throws ArgumentError Plots.check_contour_levels(1.0)
|
||||
@test_throws ArgumentError Plots.check_contour_levels((1, 2, 3))
|
||||
@test_throws ArgumentError Plots.check_contour_levels(-3)
|
||||
end
|
||||
|
||||
@testset "RecipesPipeline.preprocess_attributes!" begin
|
||||
function equal_after_pipeline(kw)
|
||||
kw′ = deepcopy(kw)
|
||||
RecipesPipeline.preprocess_attributes!(kw′)
|
||||
kw == kw′
|
||||
end
|
||||
|
||||
@test equal_after_pipeline(KW(:levels => 1))
|
||||
@test equal_after_pipeline(KW(:levels => 1:10))
|
||||
@test equal_after_pipeline(KW(:levels => [1.0, 3.0, 5.0]))
|
||||
@test_throws ArgumentError RecipesPipeline.preprocess_attributes!(
|
||||
KW(:levels => 1.0),
|
||||
)
|
||||
@test_throws ArgumentError RecipesPipeline.preprocess_attributes!(
|
||||
KW(:levels => (1, 2, 3)),
|
||||
)
|
||||
@test_throws ArgumentError RecipesPipeline.preprocess_attributes!(KW(:levels => -3))
|
||||
end
|
||||
|
||||
@testset "contour[f]" begin
|
||||
x = (-2π):0.1:(2π)
|
||||
y = (-π):0.1:π
|
||||
z = cos.(y) .* sin.(x')
|
||||
|
||||
@testset "Incorrect input" begin
|
||||
@test_throws ArgumentError contour(x, y, z, levels = 1.0)
|
||||
@test_throws ArgumentError contour(x, y, z, levels = (1, 2, 3))
|
||||
@test_throws ArgumentError contour(x, y, z, levels = -3)
|
||||
end
|
||||
|
||||
@testset "Default number" begin
|
||||
@test contour(x, y, z)[1][1].plotattributes[:levels] ==
|
||||
Plots._series_defaults[:levels]
|
||||
end
|
||||
|
||||
@testset "Number" begin
|
||||
@testset "$n contours" for n in (2, 5, 100)
|
||||
p = contour(x, y, z, levels = n)
|
||||
attr = p[1][1].plotattributes
|
||||
@test attr[:seriestype] == :contour
|
||||
@test attr[:levels] == n
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Range" begin
|
||||
levels = -1:0.5:1
|
||||
@test contour(x, y, z, levels = levels)[1][1].plotattributes[:levels] == levels
|
||||
end
|
||||
|
||||
@testset "Set of levels" begin
|
||||
levels = [-1, 0.25, 0, 0.25, 1]
|
||||
@test contour(x, y, z, levels = levels)[1][1].plotattributes[:levels] == levels
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,57 @@
|
||||
using Plots, Test
|
||||
|
||||
@testset "Plotly" begin
|
||||
@testset "Basic" begin
|
||||
@test plotly() == Plots.PlotlyBackend()
|
||||
@test backend() == Plots.PlotlyBackend()
|
||||
|
||||
p = plot(rand(10))
|
||||
@test isa(p, Plots.Plot) == true
|
||||
end
|
||||
|
||||
@testset "Contours" begin
|
||||
x = (-2π):0.1:(2π)
|
||||
y = (-π):0.1:π
|
||||
z = cos.(y) .* sin.(x')
|
||||
|
||||
@testset "Contour numbers" begin
|
||||
@testset "Default" begin
|
||||
@test Plots.plotly_series(contour(x, y, z))[1][:ncontours] ==
|
||||
Plots._series_defaults[:levels] + 2
|
||||
end
|
||||
@testset "Specified number" begin
|
||||
@test Plots.plotly_series(contour(x, y, z, levels = 10))[1][:ncontours] ==
|
||||
12
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Contour values" begin
|
||||
@testset "Range" begin
|
||||
levels = -1:0.5:1
|
||||
p = contour(x, y, z, levels = levels)
|
||||
@test p[1][1].plotattributes[:levels] == levels
|
||||
@test Plots.plotly_series(p)[1][:contours][:start] == first(levels)
|
||||
@test Plots.plotly_series(p)[1][:contours][:end] == last(levels)
|
||||
@test Plots.plotly_series(p)[1][:contours][:size] == step(levels)
|
||||
end
|
||||
|
||||
@testset "Set of contours" begin
|
||||
levels = [-1, -0.25, 0, 0.25, 1]
|
||||
levels_range =
|
||||
range(first(levels), stop = last(levels), length = length(levels))
|
||||
p = contour(x, y, z, levels = levels)
|
||||
@test p[1][1].plotattributes[:levels] == levels
|
||||
series_dict = @test_logs (
|
||||
:warn,
|
||||
"setting arbitrary contour levels with Plotly backend " *
|
||||
"is not supported; use a range to set equally-spaced contours or an " *
|
||||
"integer to set the approximate number of contours with the keyword " *
|
||||
"`levels`. Setting levels to -1.0:0.5:1.0",
|
||||
) Plots.plotly_series(p)
|
||||
@test series_dict[1][:contours][:start] == first(levels_range)
|
||||
@test series_dict[1][:contours][:end] == last(levels_range)
|
||||
@test series_dict[1][:contours][:size] == step(levels_range)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user