Compare commits
156 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b6d7d10d4 | |||
| 71cf37cc16 | |||
| f905cb9577 | |||
| b9b6439f47 | |||
| ffcdf986a3 | |||
| 43245b5eb5 | |||
| 420228c67b | |||
| f1719d6e91 | |||
| 9aa1fd5c00 | |||
| 141845aa40 | |||
| 7867df6079 | |||
| 182b937143 | |||
| 399a9b16f6 | |||
| 42aa7d8d55 | |||
| 8778119792 | |||
| 10e3f2c990 | |||
| 5e25989366 | |||
| f12d328cf7 | |||
| efc4917724 | |||
| c2bf145ff5 | |||
| c8c82811b3 | |||
| c21e133e69 | |||
| 789a7fbb88 | |||
| 888ed9f0ae | |||
| 57da253fa8 | |||
| 44a6707397 | |||
| f0a3ca4314 | |||
| 9bbd52dcc2 | |||
| f50862ac51 | |||
| 017bed1a07 | |||
| 3765d5f549 | |||
| dd28159564 | |||
| 63cdf9f8e7 | |||
| e30889aa12 | |||
| b7caec1bfe | |||
| 660786b99c | |||
| b060576209 | |||
| 7b3826c2d5 | |||
| 51d4416b00 | |||
| cfe6103f48 | |||
| bee8230079 | |||
| 3d77c59c92 | |||
| 667ed161c0 | |||
| 979f9495f1 | |||
| d29a44efa7 | |||
| 7750003033 | |||
| e673339dc4 | |||
| b20b47f8eb | |||
| 689e437bac | |||
| e6bb17dc86 | |||
| 80a97b0f26 | |||
| ffea050bc2 | |||
| 8951526d0d | |||
| 3e799fbe21 | |||
| 53e27dbc38 | |||
| 9985d303ce | |||
| ba46299088 | |||
| 9679eae662 | |||
| 7acb5a4bdb | |||
| d1428b8221 | |||
| c59a361ab3 | |||
| 8935728daa | |||
| 155ac91385 | |||
| 4403ed3860 | |||
| 712b567752 | |||
| 75be945359 | |||
| fe50a457cd | |||
| 6f821e5344 | |||
| 14cbfb5706 | |||
| a882685169 | |||
| b9b7edc72d | |||
| d0b939da4a | |||
| 2643d493a3 | |||
| c26689fcb1 | |||
| a2365f2c14 | |||
| 435ff795ca | |||
| af34fdc45a | |||
| 3bfedd844e | |||
| f726151e6e | |||
| c6c4becf7d | |||
| e2deb71988 | |||
| a717bf4f34 | |||
| 2fef7a5b84 | |||
| 12309c281b | |||
| a2a4e5b350 | |||
| 6741287ef1 | |||
| 6940f5a982 | |||
| b0bd5c13a0 | |||
| af119a0248 | |||
| 759cd7b3f2 | |||
| 5e06e0d2d2 | |||
| 85b83e1745 | |||
| 441954be35 | |||
| 11c1a23dfe | |||
| 1386435b17 | |||
| f33d135182 | |||
| 5396477082 | |||
| 5ea77cc4b6 | |||
| 45b5b33929 | |||
| 9213b09c57 | |||
| 113e616d25 | |||
| 8861c553da | |||
| 6be7995500 | |||
| 89d08606ad | |||
| e709560319 | |||
| 9eda7548d0 | |||
| 6e0522308a | |||
| 7062e8864b | |||
| 957cea2638 | |||
| 532710e6bf | |||
| 24e46e4c01 | |||
| cb3cdbf6e7 | |||
| dcceef2e52 | |||
| cbc965dc53 | |||
| f5b793f80c | |||
| d3b51703f2 | |||
| 0ecee70af2 | |||
| 061704ac6e | |||
| 3e1ce8c2fa | |||
| 1cc84672e7 | |||
| 04f502df8a | |||
| 22c3afd8a0 | |||
| d9be97fc45 | |||
| b04e6ff699 | |||
| 9c1a5548e1 | |||
| b73d7f03a7 | |||
| 106ed6b953 | |||
| cccbaa0bdc | |||
| 874dacd2c8 | |||
| a72a23b548 | |||
| 31004e8c12 | |||
| 87c471c0f5 | |||
| d3e1a423fd | |||
| 16cc743d26 | |||
| 9ccb699fca | |||
| 7e0960e7a0 | |||
| ee4fc2803b | |||
| 268c2861c9 | |||
| 15739bc0ee | |||
| e84de56f2e | |||
| 6b46e81fbd | |||
| f5de5f58ce | |||
| 3c2cfa333c | |||
| 63bc3a2b88 | |||
| 1e83bc05ee | |||
| fc51c355a5 | |||
| 59e7213c96 | |||
| 192020a93a | |||
| 5f5019d310 | |||
| f0f90d87af | |||
| 1bbe800dcd | |||
| a731ef6e2d | |||
| c2e8b5a1fa | |||
| 1a67ca897c | |||
| d1980ef978 | |||
| b3db49b4ae |
@@ -6,3 +6,4 @@ examples/.ipynb_checkpoints/*
|
||||
examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-latest.min.js
|
||||
deps/build.log
|
||||
deps/deps.jl
|
||||
|
||||
@@ -10,7 +10,36 @@
|
||||
|
||||
---
|
||||
## (current master)
|
||||
- All new development should target Julia 1.x!
|
||||
|
||||
## 0.22.1
|
||||
- push PlotsDisplay just after REPLDisplay
|
||||
|
||||
## 0.22.0
|
||||
- deprecate GLVisualize
|
||||
- allow 1-row and 1-column heatmaps
|
||||
- add portfoliodecomposition recipe from PlotRecipes
|
||||
- solve Shape bug
|
||||
- simplify PyPlot backend installation
|
||||
- fix wireframe bug in PyPlot
|
||||
- fix color bug in PyPlot
|
||||
- minor bug fixes in gr and pyplot
|
||||
|
||||
## 0.21.0
|
||||
- Compatibility with StaticArrays 0.9.0
|
||||
- Up GR min version to 0.35
|
||||
- fix :mirror
|
||||
|
||||
## 0.20.6
|
||||
- fixes for PlotDocs.jl
|
||||
- fix gr axis color argument
|
||||
- Shapes for inspectdr
|
||||
- don't load plotly js file by default
|
||||
|
||||
## 0.20.5
|
||||
- fix precompilation issue when depending on Plots
|
||||
|
||||
## 0.20.4
|
||||
- honour `html_output_format` in Juno
|
||||
|
||||
## 0.20.3
|
||||
- implement guide position in gr, pyplot and pgfplots
|
||||
@@ -153,7 +182,7 @@ Many updates, min julia 1.0
|
||||
- add `reset_defaults()` function to reset plot defaults
|
||||
- update syntax to 0.6
|
||||
- make `fill = true` fill to 0 rather than to 1
|
||||
- use new `@df` syntax in StatPlots examples
|
||||
- use new `@df` syntax in StatsPlots examples
|
||||
- allow changing the color of legend box
|
||||
- implement `title_location` for gr
|
||||
- add `hline` marker to pgfplots - fixes errorbars
|
||||
@@ -305,7 +334,7 @@ Many updates, min julia 1.0
|
||||
- added dependency on PlotThemes
|
||||
- set_theme --> theme
|
||||
- remove Compat from REQUIRE
|
||||
- warning for DataFrames without StatPlots
|
||||
- warning for DataFrames without StatsPlots
|
||||
- closeall exported and implemented for gr/pyplot
|
||||
- fix DateTime recipe
|
||||
- reset theme with theme(:none)
|
||||
@@ -427,8 +456,8 @@ Many updates, min julia 1.0
|
||||
#### 0.8.0
|
||||
|
||||
- added dependency on PlotUtils
|
||||
- BREAKING: removed DataFrames support (now in StatPlots.jl)
|
||||
- BREAKING: removed boxplot/violin/density recipes (now in StatPlots.jl)
|
||||
- BREAKING: removed DataFrames support (now in StatsPlots.jl)
|
||||
- BREAKING: removed boxplot/violin/density recipes (now in StatsPlots.jl)
|
||||
- GR:
|
||||
- inline iterm2 support
|
||||
- trisurface support
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
environment:
|
||||
matrix:
|
||||
- julia_version: 0.7
|
||||
# - julia_version: 0.7
|
||||
- julia_version: 1
|
||||
- julia_version: nightly
|
||||
|
||||
|
||||
Vendored
+15
-5
@@ -1,8 +1,18 @@
|
||||
|
||||
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
|
||||
|
||||
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
|
||||
if !isfile(local_fn)
|
||||
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
|
||||
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
|
||||
file_path = ""
|
||||
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
|
||||
global file_path
|
||||
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
|
||||
if !isfile(local_fn)
|
||||
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
|
||||
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
|
||||
isfile(local_fn) && (file_path = local_fn)
|
||||
else
|
||||
file_path = local_fn
|
||||
end
|
||||
end
|
||||
|
||||
open("deps.jl", "w") do io
|
||||
println(io, "const plotly_local_file_path = $(repr(file_path))")
|
||||
end
|
||||
|
||||
+20
-93
@@ -1,10 +1,11 @@
|
||||
module Plots
|
||||
|
||||
_current_plots_version = v"0.20.6"
|
||||
|
||||
using Reexport
|
||||
|
||||
import StaticArrays
|
||||
using StaticArrays.FixedSizeArrays
|
||||
using Dates, Printf, Statistics, Base64, LinearAlgebra
|
||||
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
|
||||
import SparseArrays: findnz
|
||||
|
||||
@reexport using RecipesBase
|
||||
@@ -18,6 +19,17 @@ import JSON
|
||||
|
||||
using Requires
|
||||
|
||||
if isfile(joinpath(@__DIR__, "..", "deps", "deps.jl"))
|
||||
include(joinpath(@__DIR__, "..", "deps", "deps.jl"))
|
||||
else
|
||||
# This is a bit dirty, but I don't really see why anyone should be forced
|
||||
# to build Plots, while it will just include exactly the below line
|
||||
# as long as `ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] = "true"` is not set.
|
||||
# If the above env is set + `plotly_local_file_path == ""``,
|
||||
# it will warn in the __init__ function to run build
|
||||
const plotly_local_file_path = ""
|
||||
end
|
||||
|
||||
export
|
||||
grid,
|
||||
bbox,
|
||||
@@ -72,7 +84,6 @@ export
|
||||
backends,
|
||||
backend_name,
|
||||
backend_object,
|
||||
add_backend,
|
||||
aliases,
|
||||
|
||||
Shape,
|
||||
@@ -168,99 +179,15 @@ include("arg_desc.jl")
|
||||
include("plotattr.jl")
|
||||
include("backends.jl")
|
||||
include("output.jl")
|
||||
include("ijulia.jl")
|
||||
include("fileio.jl")
|
||||
include("init.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
include("backends/plotly.jl")
|
||||
include("backends/gr.jl")
|
||||
include("backends/web.jl")
|
||||
|
||||
@shorthands scatter
|
||||
@shorthands bar
|
||||
@shorthands barh
|
||||
@shorthands histogram
|
||||
@shorthands barhist
|
||||
@shorthands stephist
|
||||
@shorthands scatterhist
|
||||
@shorthands histogram2d
|
||||
@shorthands density
|
||||
@shorthands heatmap
|
||||
@shorthands plots_heatmap
|
||||
@shorthands hexbin
|
||||
@shorthands sticks
|
||||
@shorthands hline
|
||||
@shorthands vline
|
||||
@shorthands hspan
|
||||
@shorthands vspan
|
||||
@shorthands ohlc
|
||||
@shorthands contour
|
||||
@shorthands contourf
|
||||
@shorthands contour3d
|
||||
@shorthands surface
|
||||
@shorthands wireframe
|
||||
@shorthands path3d
|
||||
@shorthands scatter3d
|
||||
@shorthands boxplot
|
||||
@shorthands violin
|
||||
@shorthands quiver
|
||||
@shorthands curves
|
||||
|
||||
"Plot a pie diagram"
|
||||
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
|
||||
"Plot with seriestype :path3d"
|
||||
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
|
||||
"Add title to an existing plot"
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
|
||||
"Add xlabel to an existing plot"
|
||||
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
|
||||
|
||||
"Add ylabel to an existing plot"
|
||||
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
|
||||
|
||||
"Set xlims for an existing plot"
|
||||
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
|
||||
|
||||
"Set ylims for an existing plot"
|
||||
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
|
||||
|
||||
"Set zlims for an existing plot"
|
||||
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
|
||||
|
||||
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
|
||||
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
|
||||
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
|
||||
|
||||
|
||||
"Set xticks for an existing plot"
|
||||
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
|
||||
|
||||
"Set yticks for an existing plot"
|
||||
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
|
||||
|
||||
xticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
|
||||
yticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
|
||||
|
||||
"Add annotations to an existing plot"
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
|
||||
|
||||
"Flip the current plots' x axis"
|
||||
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
|
||||
|
||||
"Flip the current plots' y axis"
|
||||
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
|
||||
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
|
||||
include("shorthands.jl")
|
||||
|
||||
let PlotOrSubplot = Union{Plot, Subplot}
|
||||
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
|
||||
+3
-3
@@ -93,13 +93,13 @@ end
|
||||
|
||||
|
||||
|
||||
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
|
||||
# write out html to view the gif
|
||||
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
ext = file_extension(agif.filename)
|
||||
write(io, if ext == "gif"
|
||||
"<img src=\"$(relpath(agif.filename))?$(rand())>\" />"
|
||||
"<img src=\"$(relpath(agif.filename))\" />"
|
||||
elseif ext in ("mov", "mp4")
|
||||
"<video controls><source src=\"$(relpath(agif.filename))?$(rand())>\" type=\"video/$ext\"></video>"
|
||||
"<video controls><source src=\"$(relpath(agif.filename)) type=\"video/$ext\"></video>"
|
||||
else
|
||||
error("Cannot show animation with extension $ext: $agif")
|
||||
end)
|
||||
|
||||
+24
-24
@@ -2,7 +2,7 @@
|
||||
const _arg_desc = KW(
|
||||
|
||||
# series args
|
||||
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
|
||||
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
|
||||
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
|
||||
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
|
||||
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
|
||||
@@ -10,7 +10,7 @@ const _arg_desc = KW(
|
||||
:linewidth => "Number. Width of the line (in pixels)",
|
||||
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
|
||||
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
|
||||
:fillrange => "Number or AbstractVector. Fills area from this to y for line-types, sets the base for bar/stick types, and similar for other types.",
|
||||
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
|
||||
: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).",
|
||||
@@ -21,7 +21,7 @@ const _arg_desc = KW(
|
||||
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
|
||||
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
|
||||
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(min(x), stop = extrema(x), length = 25)`",
|
||||
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`",
|
||||
:smooth => "Bool. Add a regression line?",
|
||||
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
|
||||
:x => "Various. Input data. First Dimension",
|
||||
@@ -29,13 +29,13 @@ const _arg_desc = KW(
|
||||
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
|
||||
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or 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}. Number of levels (or x-levels/y-levels) for a contour type.",
|
||||
: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.",
|
||||
: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`).",
|
||||
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
|
||||
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
|
||||
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
|
||||
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
|
||||
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
|
||||
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
|
||||
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
|
||||
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
|
||||
@@ -43,12 +43,12 @@ const _arg_desc = KW(
|
||||
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
|
||||
:weights => "AbstractVector. Used in histogram types for weighted counts.",
|
||||
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
|
||||
:contour_labels => "Bool. Show labels at the contour lines?",
|
||||
:contour_labels => "Bool. Show labels at the contour lines?",
|
||||
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
|
||||
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
|
||||
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
|
||||
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
|
||||
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
|
||||
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
|
||||
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
|
||||
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
|
||||
|
||||
# plot args
|
||||
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
|
||||
@@ -63,11 +63,11 @@ const _arg_desc = KW(
|
||||
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
|
||||
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
|
||||
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
|
||||
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
|
||||
:dpi => "Number. Dots Per Inch of output figures",
|
||||
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
|
||||
:dpi => "Number. Dots Per Inch of output figures",
|
||||
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
|
||||
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
|
||||
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
|
||||
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
|
||||
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
|
||||
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
|
||||
|
||||
# subplot args
|
||||
@@ -98,7 +98,7 @@ const _arg_desc = KW(
|
||||
:legendfont => "Font. Font of legend items.",
|
||||
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
|
||||
:projection => "Symbol or String. '3d' or 'polar'",
|
||||
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
|
||||
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units.",
|
||||
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
|
||||
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
|
||||
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
|
||||
@@ -110,14 +110,14 @@ const _arg_desc = KW(
|
||||
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
|
||||
|
||||
# axis args
|
||||
:guide => "String. Axis guide (label).",
|
||||
:guide => "String. Axis guide (label).",
|
||||
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
|
||||
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
|
||||
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
|
||||
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
|
||||
:rotation => "Number. Degrees rotation of tick labels.",
|
||||
:flip => "Bool. Should we flip (reverse) the axis?",
|
||||
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
|
||||
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
|
||||
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
|
||||
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
|
||||
:rotation => "Number. Degrees rotation of tick labels.",
|
||||
:flip => "Bool. Should we flip (reverse) the axis?",
|
||||
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
|
||||
:tickfontfamily => "String or Symbol. Font family of tick labels.",
|
||||
:tickfontsize => "Integer. Font pointsize of tick labels.",
|
||||
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
|
||||
|
||||
+2
-2
@@ -1050,8 +1050,8 @@ function preprocessArgs!(plotattributes::KW)
|
||||
|
||||
# warnings for moved recipes
|
||||
st = get(plotattributes, :seriestype, :path)
|
||||
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
|
||||
@warn("seriestype $st has been moved to StatPlots. To use: \`Pkg.add(\"StatPlots\"); using StatPlots\`")
|
||||
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots)
|
||||
@warn("seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`")
|
||||
end
|
||||
|
||||
return
|
||||
|
||||
+1
-1
@@ -459,7 +459,7 @@ const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter
|
||||
|
||||
function default_should_widen(axis::Axis)
|
||||
should_widen = false
|
||||
if !is_2tuple(axis[:lims])
|
||||
if !(is_2tuple(axis[:lims]) || axis[:lims] == :round)
|
||||
for sp in axis.sps
|
||||
for series in series_list(sp)
|
||||
if series.plotattributes[:seriestype] in _widen_seriestypes
|
||||
|
||||
+367
-120
@@ -7,16 +7,20 @@ const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
|
||||
const _backends = Symbol[]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
const _default_backends = (:none, :gr, :plotly)
|
||||
const _backendPackage = Dict{Symbol, Symbol}()
|
||||
|
||||
const _backend_packages = Dict{Symbol, Symbol}()
|
||||
|
||||
"Returns a list of supported backends"
|
||||
backends() = _backends
|
||||
|
||||
"Returns the name of the current backend"
|
||||
backend_name() = CURRENT_BACKEND.sym
|
||||
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
|
||||
backend_package(pkg::Symbol) = pkg in _default_backends ? :Plots : Symbol("Plots", _backendPackage[pkg])
|
||||
backend_package_name(sym::Symbol) = sym in _default_backends ? :Plots : _backendPackage[sym]
|
||||
|
||||
function _backend_instance(sym::Symbol)::AbstractBackend
|
||||
haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
|
||||
end
|
||||
|
||||
backend_package_name(sym::Symbol) = _backend_packages[sym]
|
||||
|
||||
macro init_backend(s)
|
||||
package_str = string(s)
|
||||
@@ -26,13 +30,13 @@ macro init_backend(s)
|
||||
esc(quote
|
||||
struct $T <: AbstractBackend end
|
||||
export $sym
|
||||
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
|
||||
$sym(; kw...) = (default(; kw...); backend($T()))
|
||||
backend_name(::$T) = Symbol($str)
|
||||
backend_package_name(pkg::$T) = backend_package_name(Symbol($str))
|
||||
push!(_backends, Symbol($str))
|
||||
_backendType[Symbol($str)] = $T
|
||||
_backendSymbol[$T] = Symbol($str)
|
||||
_backendPackage[Symbol($str)] = Symbol($package_str)
|
||||
_backend_packages[Symbol($str)] = Symbol($package_str)
|
||||
# include("backends/" * $str * ".jl")
|
||||
end)
|
||||
end
|
||||
@@ -42,12 +46,6 @@ end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function add_backend(pkg::Symbol)
|
||||
@info("To do a standard install of $pkg, copy and run this:\n\n")
|
||||
println(add_backend_string(_backend_instance(pkg)))
|
||||
println()
|
||||
end
|
||||
|
||||
# don't do anything as a default
|
||||
_create_backend_figure(plt::Plot) = nothing
|
||||
_prepare_plot_object(plt::Plot) = nothing
|
||||
@@ -138,33 +136,27 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function pickDefaultBackend()
|
||||
_fallback_default_backend() = backend(GRBackend())
|
||||
|
||||
function _pick_default_backend()
|
||||
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
|
||||
if env_default != ""
|
||||
sym = Symbol(lowercase(env_default))
|
||||
if sym in _backends
|
||||
if sym in _initialized_backends
|
||||
return backend(sym)
|
||||
backend(sym)
|
||||
else
|
||||
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
|
||||
_fallback_default_backend()
|
||||
end
|
||||
else
|
||||
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
|
||||
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t" *
|
||||
join(sort(_backends), "\n\t"))
|
||||
_fallback_default_backend()
|
||||
end
|
||||
else
|
||||
_fallback_default_backend()
|
||||
end
|
||||
|
||||
# the ordering/inclusion of this package list is my semi-arbitrary guess at
|
||||
# which one someone will want to use if they have the package installed...accounting for
|
||||
# features, speed, and robustness
|
||||
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
|
||||
# if pkgstr in keys(Pkg.installed())
|
||||
# return backend(Symbol(lowercase(pkgstr)))
|
||||
# end
|
||||
# end
|
||||
|
||||
# the default if nothing else is installed
|
||||
backend(:gr)
|
||||
end
|
||||
|
||||
|
||||
@@ -174,13 +166,11 @@ end
|
||||
Returns the current plotting package name. Initializes package on first call.
|
||||
"""
|
||||
function backend()
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
_pick_default_backend()
|
||||
end
|
||||
|
||||
global CURRENT_BACKEND
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
end
|
||||
|
||||
CURRENT_BACKEND.pkg
|
||||
CURRENT_BACKEND.pkg
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -188,20 +178,13 @@ Set the plot backend.
|
||||
"""
|
||||
function backend(pkg::AbstractBackend)
|
||||
sym = backend_name(pkg)
|
||||
if sym in _initialized_backends
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
else
|
||||
# try
|
||||
_initialize_backend(pkg)
|
||||
push!(_initialized_backends, sym)
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
# catch
|
||||
# add_backend(sym)
|
||||
# end
|
||||
if !(sym in _initialized_backends)
|
||||
_initialize_backend(pkg)
|
||||
push!(_initialized_backends, sym)
|
||||
end
|
||||
backend()
|
||||
CURRENT_BACKEND.sym = sym
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
pkg
|
||||
end
|
||||
|
||||
function backend(sym::Symbol)
|
||||
@@ -209,15 +192,15 @@ function backend(sym::Symbol)
|
||||
backend(_backend_instance(sym))
|
||||
else
|
||||
@warn("`:$sym` is not a supported backend.")
|
||||
backend()
|
||||
end
|
||||
backend()
|
||||
end
|
||||
|
||||
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
|
||||
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize]
|
||||
|
||||
function warn_on_deprecated_backend(bsym::Symbol)
|
||||
if bsym in _deprecated_backends
|
||||
@warn("Backend $bsym has been deprecated. It may not work as originally intended.")
|
||||
@warn("Backend $bsym has been deprecated.")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -268,17 +251,11 @@ end
|
||||
|
||||
|
||||
|
||||
# @init_backend Immerse
|
||||
# @init_backend Gadfly
|
||||
@init_backend PyPlot
|
||||
# @init_backend Qwt
|
||||
@init_backend UnicodePlots
|
||||
# @init_backend Winston
|
||||
# @init_backend Bokeh
|
||||
@init_backend Plotly
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend GLVisualize
|
||||
@init_backend PGFPlots
|
||||
@init_backend InspectDR
|
||||
@init_backend HDF5
|
||||
@@ -322,72 +299,189 @@ function _initialize_backend(pkg::AbstractBackend)
|
||||
end
|
||||
end
|
||||
|
||||
function add_backend_string(pkg::AbstractBackend)
|
||||
sym = backend_package_name(pkg)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("$sym")
|
||||
"""
|
||||
end
|
||||
_initialize_backend(pkg::GRBackend) = nothing
|
||||
|
||||
_initialize_backend(pkg::PlotlyBackend) = nothing
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# glvisualize
|
||||
# gr
|
||||
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval Main begin
|
||||
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
|
||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
|
||||
import FileIO, Images
|
||||
export GLVisualize
|
||||
import Reactive: Signal
|
||||
import GLAbstraction: Style
|
||||
import GLVisualize: visualize
|
||||
import Plots.GL
|
||||
import UnicodeFun
|
||||
end
|
||||
end
|
||||
const _gr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:layout,
|
||||
:title, :window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip,
|
||||
:match_dimensions,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontrotation, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
|
||||
:legendfontrotation, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
|
||||
:tickfontrotation, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
|
||||
:guidefontrotation, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:aspect_ratio,
|
||||
:normalize, :weights,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _gr_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :path3d, :scatter3d, :surface, :wireframe,
|
||||
:shape
|
||||
]
|
||||
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _gr_marker = _allMarkers
|
||||
const _gr_scale = [:identity, :log10]
|
||||
is_marker_supported(::GRBackend, shape::Shape) = true
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# hdf5
|
||||
# plotly
|
||||
|
||||
function _initialize_backend(::HDF5Backend)
|
||||
@eval Main begin
|
||||
import HDF5
|
||||
export HDF5
|
||||
end
|
||||
end
|
||||
const _plotly_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:foreground_color_title,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:title, :title_location,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :gridalpha, :gridlinewidth,
|
||||
:legend, :colorbar, :colorbar_title,
|
||||
:marker_z, :fill_z, :line_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
# :contours,
|
||||
:aspect_ratio,
|
||||
:hover,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:clims,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
|
||||
const _plotly_seriestype = [
|
||||
:path, :scatter, :pie, :heatmap,
|
||||
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
|
||||
:straightline
|
||||
]
|
||||
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _plotly_marker = [
|
||||
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
|
||||
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
|
||||
]
|
||||
const _plotly_scale = [:identity, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# PGFPLOTS
|
||||
# pgfplots
|
||||
|
||||
function add_backend_string(::PGFPlotsBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("PGFPlots")
|
||||
Pkg.build("PGFPlots")
|
||||
"""
|
||||
end
|
||||
const _pgfplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
# :foreground_color_legend,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
# :bar_width, :bar_edges,
|
||||
:title,
|
||||
# :window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
:colorbar, :colorbar_title,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
:tick_direction,
|
||||
:framestyle,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# plotlyjs
|
||||
|
||||
function add_backend_string(::PlotlyJSBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("PlotlyJS")
|
||||
Pkg.add("Rsvg")
|
||||
import Blink
|
||||
Blink.AtomShell.install()
|
||||
"""
|
||||
function _initialize_backend(pkg::PlotlyJSBackend)
|
||||
@eval Main begin
|
||||
import PlotlyJS, ORCA
|
||||
export PlotlyJS
|
||||
end
|
||||
end
|
||||
|
||||
const _plotlyjs_attr = _plotly_attr
|
||||
const _plotlyjs_seriestype = _plotly_seriestype
|
||||
const _plotlyjs_style = _plotly_style
|
||||
const _plotlyjs_marker = _plotly_marker
|
||||
const _plotlyjs_scale = _plotly_scale
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pyplot
|
||||
|
||||
function _initialize_backend(::PyPlotBackend)
|
||||
@eval Main begin
|
||||
import PyPlot, PyCall
|
||||
import LaTeXStrings
|
||||
import PyPlot
|
||||
|
||||
export PyPlot
|
||||
|
||||
@@ -396,25 +490,178 @@ function _initialize_backend(::PyPlotBackend)
|
||||
end
|
||||
end
|
||||
|
||||
function add_backend_string(::PyPlotBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.add("PyCall")
|
||||
Pkg.add("LaTeXStrings")
|
||||
withenv("PYTHON" => "") do
|
||||
Pkg.build("PyCall")
|
||||
Pkg.build("PyPlot")
|
||||
end
|
||||
"""
|
||||
end
|
||||
const _pyplot_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
:stride,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
:path, :steppre, :steppost, :shape, :straightline,
|
||||
:scatter, :hexbin, #:histogram2d, :histogram,
|
||||
# :bar,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _pyplot_marker = vcat(_allMarkers, :pixel)
|
||||
const _pyplot_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# unicodeplots
|
||||
function add_backend_string(::UnicodePlotsBackend)
|
||||
"""
|
||||
using Pkg
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.build("UnicodePlots")
|
||||
"""
|
||||
end
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor,
|
||||
:seriesalpha,
|
||||
:linestyle,
|
||||
:markershape,
|
||||
:bins,
|
||||
:title,
|
||||
:guide, :lims,
|
||||
])
|
||||
const _unicodeplots_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
# :bar,
|
||||
:shape,
|
||||
:histogram2d,
|
||||
:spy
|
||||
]
|
||||
const _unicodeplots_style = [:auto, :solid]
|
||||
const _unicodeplots_marker = [:none, :auto, :circle]
|
||||
const _unicodeplots_scale = [:identity]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# hdf5
|
||||
|
||||
const _hdf5_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
])
|
||||
const _hdf5_seriestype = [
|
||||
:path, :steppre, :steppost, :shape, :straightline,
|
||||
:scatter, :hexbin, #:histogram2d, :histogram,
|
||||
# :bar,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _hdf5_marker = vcat(_allMarkers, :pixel)
|
||||
const _hdf5_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# inspectdr
|
||||
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_grid,
|
||||
:foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokestyle, #Causes warning not to have it... what is this?
|
||||
:fillcolor, :fillalpha, #:fillrange,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location,
|
||||
:window_title,
|
||||
:guide, :lims, :scale, #:ticks, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :legend, #:colorbar,
|
||||
# :marker_z,
|
||||
# :line_z,
|
||||
# :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
:dpi,
|
||||
# :colorbar_title,
|
||||
])
|
||||
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _inspectdr_seriestype = [
|
||||
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
|
||||
]
|
||||
#see: _allMarkers, _shape_keys
|
||||
const _inspectdr_marker = Symbol[
|
||||
:none, :auto,
|
||||
:circle, :rect, :diamond,
|
||||
:cross, :xcross,
|
||||
:utriangle, :dtriangle, :rtriangle, :ltriangle,
|
||||
:pentagon, :hexagon, :heptagon, :octagon,
|
||||
:star4, :star5, :star6, :star7, :star8,
|
||||
:vline, :hline, :+, :x,
|
||||
]
|
||||
|
||||
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+26
-75
@@ -3,68 +3,10 @@
|
||||
|
||||
# significant contributions by @jheinen
|
||||
|
||||
const _gr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:layout,
|
||||
:title, :window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip,
|
||||
:match_dimensions,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontrotation, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
|
||||
:legendfontrotation, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
|
||||
:tickfontrotation, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
|
||||
:guidefontrotation, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar, :colorbar_title,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:aspect_ratio,
|
||||
:normalize, :weights,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:arrow,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _gr_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :path3d, :scatter3d, :surface, :wireframe,
|
||||
:shape
|
||||
]
|
||||
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _gr_marker = _allMarkers
|
||||
const _gr_scale = [:identity, :log10]
|
||||
is_marker_supported(::GRBackend, shape::Shape) = true
|
||||
|
||||
function add_backend_string(::GRBackend)
|
||||
"""
|
||||
Pkg.add("GR")
|
||||
Pkg.build("GR")
|
||||
"""
|
||||
end
|
||||
|
||||
import GR
|
||||
export GR
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
const gr_linetype = KW(
|
||||
@@ -661,11 +603,19 @@ function _update_min_padding!(sp::Subplot{GRBackend})
|
||||
end
|
||||
# Add margin for x label
|
||||
if sp[:xaxis][:guide] != ""
|
||||
bottompad += 4mm
|
||||
if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true)
|
||||
toppad += 4mm
|
||||
else
|
||||
bottompad += 4mm
|
||||
end
|
||||
end
|
||||
# Add margin for y label
|
||||
if sp[:yaxis][:guide] != ""
|
||||
leftpad += 4mm
|
||||
if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true)
|
||||
rightpad += 4mm
|
||||
else
|
||||
leftpad += 4mm
|
||||
end
|
||||
end
|
||||
if sp[:colorbar_title] != ""
|
||||
rightpad += 4mm
|
||||
@@ -722,7 +672,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
outside_ticks = true
|
||||
for ax in (sp[:xaxis], sp[:yaxis])
|
||||
v = series[ax[:letter]]
|
||||
if diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
|
||||
if length(v) > 1 && diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
|
||||
@warn("GR: heatmap only supported with equally spaced data.")
|
||||
end
|
||||
end
|
||||
@@ -855,12 +805,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
# axis lines
|
||||
if xaxis[:showaxis]
|
||||
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
|
||||
gr_set_line(1, :solid, xaxis[:foreground_color_border])
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(xspine_segs)...)
|
||||
end
|
||||
if yaxis[:showaxis]
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
|
||||
gr_set_line(1, :solid, yaxis[:foreground_color_border])
|
||||
GR.setclip(0)
|
||||
gr_polyline(coords(yspine_segs)...)
|
||||
end
|
||||
@@ -962,7 +912,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
if xaxis[:guide] != ""
|
||||
gr_set_font(guidefont(xaxis))
|
||||
if xaxis[:guide_position] == :top
|
||||
if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
gr_text(gr_view_xcenter(), viewport_subplot[4], xaxis[:guide])
|
||||
else
|
||||
@@ -974,7 +924,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
if yaxis[:guide] != ""
|
||||
gr_set_font(guidefont(yaxis))
|
||||
GR.setcharup(-1, 0)
|
||||
if yaxis[:guide_position] == :left
|
||||
if yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[:mirror] == true)
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
|
||||
gr_text(viewport_subplot[2], gr_view_ycenter(), yaxis[:guide])
|
||||
else
|
||||
@@ -1080,16 +1030,13 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
else
|
||||
h = series[:levels] > 1 ? range(zmin, stop=zmax, length=series[:levels]) : [(zmin + zmax) / 2]
|
||||
end
|
||||
GR.setlinetype(gr_linetype[get_linestyle(series)])
|
||||
GR.setlinewidth(max(0, get_linewidth(series) / (sum(gr_plot_size) * 0.001)))
|
||||
if series[:fillrange] != nothing
|
||||
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
|
||||
GR.contourf(x, y, h, z, series[:contour_labels] == true ? 1 : 0)
|
||||
else
|
||||
GR.setlinetype(gr_linetype[get_linestyle(series)])
|
||||
GR.setlinewidth(max(0, get_linewidth(series) / (sum(gr_plot_size) * 0.001)))
|
||||
if plot_color(series[:linecolor]) == [plot_color(:black)]
|
||||
GR.contour(x, y, h, z, 0 + (series[:contour_labels] == true ? 1 : 0))
|
||||
else
|
||||
GR.contour(x, y, h, z, 1000 + (series[:contour_labels] == true ? 1 : 0))
|
||||
end
|
||||
coff = plot_color(series[:linecolor]) == [plot_color(:black)] ? 0 : 1000
|
||||
GR.contour(x, y, h, z, coff + (series[:contour_labels] == true ? 1 : 0))
|
||||
end
|
||||
|
||||
# create the colorbar of contour levels
|
||||
@@ -1109,7 +1056,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
if length(x) == length(y) == length(z)
|
||||
GR.trisurface(x, y, z)
|
||||
else
|
||||
GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
||||
try
|
||||
GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
||||
catch
|
||||
GR.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
||||
end
|
||||
end
|
||||
else
|
||||
GR.setfillcolorind(0)
|
||||
|
||||
+50
-62
@@ -16,16 +16,19 @@ Read from .hdf5 file using:
|
||||
|
||||
#==TODO
|
||||
===============================================================================
|
||||
1. Support more features
|
||||
- SeriesAnnotations & GridLayout known to be missing.
|
||||
3. Improve error handling.
|
||||
1. Support more features.
|
||||
- GridLayout known not to be working.
|
||||
2. Improve error handling.
|
||||
- Will likely crash if file format is off.
|
||||
2. Save data in a folder parallel to "plot".
|
||||
3. Save data in a folder parallel to "plot".
|
||||
- Will make it easier for users to locate data.
|
||||
- Use HDF5 reference to link data?
|
||||
3. Develop an actual versioned file format.
|
||||
4. Develop an actual versioned file format.
|
||||
- Should have some form of backward compatibility.
|
||||
- Should be reliable for archival purposes.
|
||||
5. Fix construction of plot object with hdf5plot_read.
|
||||
- Not building object correctly when backends do not natively support
|
||||
a certain feature (ex: :steppre)
|
||||
==#
|
||||
|
||||
import FixedPointNumbers: N0f8 #In core Julia
|
||||
@@ -56,53 +59,13 @@ const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
|
||||
|
||||
#Simple sub-structures that can just be written out using _hdf5plot_gwritefields:
|
||||
const HDF5PLOT_SIMPLESUBSTRUCT = Union{Font, BoundingBox,
|
||||
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText
|
||||
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText,
|
||||
Shape,
|
||||
}
|
||||
|
||||
|
||||
#==
|
||||
===============================================================================#
|
||||
|
||||
const _hdf5_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
])
|
||||
const _hdf5_seriestype = [
|
||||
:path, :steppre, :steppost, :shape, :straightline,
|
||||
:scatter, :hexbin, #:histogram2d, :histogram,
|
||||
# :bar,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _hdf5_marker = vcat(_allMarkers, :pixel)
|
||||
const _hdf5_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::HDF5Backend, shape::Shape) = true
|
||||
|
||||
if length(HDF5PLOT_MAP_TELEM2STR) < 1
|
||||
@@ -125,7 +88,8 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1
|
||||
"GRIDLAYOUT" => GridLayout,
|
||||
"ROOTLAYOUT" => RootLayout,
|
||||
"SERIESANNOTATIONS" => SeriesAnnotations,
|
||||
# "PLOTTEXT" => PlotText,
|
||||
"PLOTTEXT" => PlotText,
|
||||
"SHAPE" => Shape,
|
||||
"COLORGRADIENT" => ColorGradient,
|
||||
"AXIS" => Axis,
|
||||
"SURFACE" => Surface,
|
||||
@@ -284,6 +248,14 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _hdf5plot_gwrite(grp, k::String, v) #Default
|
||||
T = typeof(v)
|
||||
if !(T <: Number || T <: String)
|
||||
tstr = string(T)
|
||||
path = HDF5.name(grp) * "/" * k
|
||||
@info("Type not supported: $tstr\npath: $path")
|
||||
# @show v
|
||||
return
|
||||
end
|
||||
grp[k] = v
|
||||
_hdf5plot_writetype(grp, k, HDF5PlotNative)
|
||||
end
|
||||
@@ -338,10 +310,6 @@ function _hdf5plot_gwrite(grp, k::String, v::Colorant)
|
||||
end
|
||||
#Custom vector (when not using simple numeric type):
|
||||
function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
|
||||
if "annotations" == k;
|
||||
return #Hack. Does not yet support annotations.
|
||||
end
|
||||
|
||||
vgrp = HDF5.g_create(grp, k)
|
||||
_hdf5plot_writetype(vgrp, Array) #ANY
|
||||
sz = size(v)
|
||||
@@ -351,7 +319,7 @@ function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
|
||||
coord = lidx[iter]
|
||||
elem = v[iter]
|
||||
idxstr = join(coord, "_")
|
||||
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
|
||||
_hdf5plot_gwrite(vgrp, "v$idxstr", elem)
|
||||
end
|
||||
|
||||
_hdf5plot_gwrite(vgrp, "dim", [sz...])
|
||||
@@ -402,10 +370,6 @@ end
|
||||
# return
|
||||
# end
|
||||
|
||||
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
|
||||
#Currently no support for SeriesAnnotations
|
||||
return
|
||||
end
|
||||
function _hdf5plot_gwrite(grp, k::String, v::Subplot)
|
||||
grp = HDF5.g_create(grp, k)
|
||||
_hdf5plot_gwrite(grp, "index", v[:subplot_index])
|
||||
@@ -528,6 +492,29 @@ function _hdf5plot_read(grp, k::String, T::Type{HDF5CTuple}, dtid)
|
||||
v = _hdf5plot_read(grp, k, Array, dtid)
|
||||
return tuple(v...)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{PlotText}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
str = _hdf5plot_read(grp, "str")
|
||||
font = _hdf5plot_read(grp, "font")
|
||||
return PlotText(str, font)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{SeriesAnnotations}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
strs = _hdf5plot_read(grp, "strs")
|
||||
font = _hdf5plot_read(grp, "font")
|
||||
baseshape = _hdf5plot_read(grp, "baseshape")
|
||||
scalefactor = _hdf5plot_read(grp, "scalefactor")
|
||||
return SeriesAnnotations(strs, font, baseshape, scalefactor)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{Shape}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
x = _hdf5plot_read(grp, "x")
|
||||
y = _hdf5plot_read(grp, "y")
|
||||
return Shape(x, y)
|
||||
end
|
||||
function _hdf5plot_read(grp, k::String, T::Type{ColorGradient}, dtid)
|
||||
grp = HDF5.g_open(grp, k)
|
||||
|
||||
@@ -601,11 +588,6 @@ end
|
||||
function _hdf5plot_read(sp::Subplot, subpath::String, f)
|
||||
f = f::HDF5.HDF5File #Assert
|
||||
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
|
||||
kwlist = KW()
|
||||
_hdf5plot_read(grp, kwlist)
|
||||
_hdf5_merge!(sp.attr, kwlist)
|
||||
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list"))
|
||||
nseries = _hdf5plot_readcount(grp)
|
||||
|
||||
@@ -617,6 +599,12 @@ function _hdf5plot_read(sp::Subplot, subpath::String, f)
|
||||
_hdf5_merge!(sp.series_list[end].plotattributes, kwlist)
|
||||
end
|
||||
|
||||
#Perform after adding series... otherwise values get overwritten:
|
||||
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
|
||||
kwlist = KW()
|
||||
_hdf5plot_read(grp, kwlist)
|
||||
_hdf5_merge!(sp.attr, kwlist)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@@ -14,61 +14,6 @@ Add in functionality to Plots.jl:
|
||||
=#
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
#TODO: remove features
|
||||
const _inspectdr_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_grid,
|
||||
:foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokestyle, #Causes warning not to have it... what is this?
|
||||
:fillcolor, :fillalpha, #:fillrange,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location,
|
||||
:window_title,
|
||||
:guide, :lims, :scale, #:ticks, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, #:gridalpha, :gridstyle, :gridlinewidth, #alhpa & linewidth are per plot - not per subplot
|
||||
:legend, #:legendtitle, :colorbar,
|
||||
# :marker_z,
|
||||
# :line_z,
|
||||
# :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
:dpi,
|
||||
# :colorbar_title,
|
||||
])
|
||||
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _inspectdr_seriestype = [
|
||||
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
|
||||
]
|
||||
#see: _allMarkers, _shape_keys
|
||||
const _inspectdr_marker = Symbol[
|
||||
:none, :auto,
|
||||
:circle, :rect, :diamond,
|
||||
:cross, :xcross,
|
||||
:utriangle, :dtriangle, :rtriangle, :ltriangle,
|
||||
:pentagon, :hexagon, :heptagon, :octagon,
|
||||
:star4, :star5, :star6, :star7, :star8,
|
||||
:vline, :hline, :+, :x,
|
||||
]
|
||||
|
||||
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
is_marker_supported(::InspectDRBackend, shape::Shape) = true
|
||||
|
||||
|
||||
@@ -2,47 +2,6 @@
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
const _pgfplots_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
# :foreground_color_legend,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
# :bar_width, :bar_edges,
|
||||
:title,
|
||||
# :window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
:colorbar, :colorbar_title,
|
||||
:fill_z, :line_z, :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
:tick_direction,
|
||||
:framestyle,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
|
||||
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
|
||||
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
const _pgfplots_linestyles = KW(
|
||||
@@ -446,7 +405,7 @@ function pgf_axis(sp::Subplot, letter)
|
||||
if framestyle == :zerolines
|
||||
push!(style, string("extra ", letter, " ticks = 0"))
|
||||
push!(style, string("extra ", letter, " tick labels = "))
|
||||
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
|
||||
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}"))
|
||||
end
|
||||
|
||||
if !axis[:showaxis]
|
||||
@@ -455,7 +414,7 @@ function pgf_axis(sp::Subplot, letter)
|
||||
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
|
||||
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
|
||||
else
|
||||
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}"))
|
||||
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}"))
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
|
||||
+23
-85
@@ -1,60 +1,6 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
const _plotly_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
:foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:foreground_color_title,
|
||||
:label,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:title, :title_location,
|
||||
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
|
||||
:titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :gridalpha, :gridlinewidth,
|
||||
:legend, :colorbar, :colorbar_title,
|
||||
:marker_z, :fill_z, :line_z, :levels,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
# :contours,
|
||||
:aspect_ratio,
|
||||
:hover,
|
||||
:inset_subplots,
|
||||
:bar_width,
|
||||
:clims,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
|
||||
const _plotly_seriestype = [
|
||||
:path, :scatter, :pie, :heatmap,
|
||||
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
|
||||
:straightline
|
||||
]
|
||||
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _plotly_marker = [
|
||||
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
|
||||
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
|
||||
]
|
||||
const _plotly_scale = [:identity, :log10]
|
||||
is_subplot_supported(::PlotlyBackend) = true
|
||||
# is_string_supported(::PlotlyBackend) = true
|
||||
const _plotly_framestyles = [:box, :axes, :zerolines, :grid, :none]
|
||||
@@ -71,30 +17,9 @@ end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
const plotly_remote_file_path = "https://cdn.plot.ly/plotly-latest.min.js"
|
||||
|
||||
|
||||
const _plotly_js_path = joinpath(dirname(@__FILE__), "..", "..", "deps", "plotly-latest.min.js")
|
||||
const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
|
||||
|
||||
_js_code = open(read, _plotly_js_path, "r")
|
||||
|
||||
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
|
||||
_js_script = """
|
||||
<script type='text/javascript'>
|
||||
define('plotly', function(require, exports, module) {
|
||||
$(_js_code)
|
||||
});
|
||||
require(['plotly'], function(Plotly) {
|
||||
window.Plotly = Plotly;
|
||||
});
|
||||
</script>
|
||||
"""
|
||||
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
display("text/html", _js_script)
|
||||
end
|
||||
|
||||
# if isatom()
|
||||
# import Atom
|
||||
# Atom.@msg evaljs(_js_code)
|
||||
@@ -102,8 +27,6 @@ end
|
||||
using UUIDs
|
||||
|
||||
push!(_initialized_backends, :plotly)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _plotly_legend_pos = KW(
|
||||
@@ -115,7 +38,7 @@ const _plotly_legend_pos = KW(
|
||||
:bottomright => [1., 0.],
|
||||
:topright => [1., 1.],
|
||||
:topleft => [0., 1.]
|
||||
)
|
||||
)
|
||||
|
||||
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
|
||||
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
|
||||
@@ -882,12 +805,27 @@ plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt))
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _use_remote = Ref(false)
|
||||
const ijulia_initialized = Ref(false)
|
||||
|
||||
function html_head(plt::Plot{PlotlyBackend})
|
||||
jsfilename = _use_remote[] ? _plotly_js_path_remote : ("file://" * _plotly_js_path)
|
||||
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
|
||||
"<script src=\"$jsfilename\"></script>"
|
||||
local_file = ("file://" * plotly_local_file_path)
|
||||
plotly = use_local_dependencies[] ? local_file : plotly_remote_file_path
|
||||
if isijulia() && !ijulia_initialized[]
|
||||
# using requirejs seems to be key to load a js depency in IJulia!
|
||||
# https://requirejs.org/docs/start.html
|
||||
# https://github.com/JuliaLang/IJulia.jl/issues/345
|
||||
display("text/html", """
|
||||
<script type="text/javascript">
|
||||
requirejs([$(repr(plotly))], function(p) {
|
||||
window.Plotly = p
|
||||
});
|
||||
</script>
|
||||
""")
|
||||
ijulia_initialized[] = true
|
||||
end
|
||||
# IJulia just needs one initialization
|
||||
isijulia() && return ""
|
||||
return "<script src=$(repr(plotly))></script>"
|
||||
end
|
||||
|
||||
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
|
||||
@@ -908,8 +846,8 @@ end
|
||||
|
||||
function js_body(plt::Plot{PlotlyBackend}, uuid)
|
||||
js = """
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
|
||||
const _plotlyjs_attr = _plotly_attr
|
||||
const _plotlyjs_seriestype = _plotly_seriestype
|
||||
const _plotlyjs_style = _plotly_style
|
||||
const _plotlyjs_marker = _plotly_marker
|
||||
const _plotlyjs_scale = _plotly_scale
|
||||
# https://github.com/sglyon/PlotlyJS.jl
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
|
||||
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
|
||||
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
|
||||
PlotlyJS.SyncPlot(PlotlyJS.Plot(), options = current().o.options)
|
||||
else
|
||||
PlotlyJS.plot()
|
||||
end
|
||||
@@ -56,23 +49,11 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
|
||||
if isijulia() && !_use_remote[]
|
||||
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
|
||||
else
|
||||
show(io, MIME("text/html"), plt.o)
|
||||
end
|
||||
end
|
||||
|
||||
function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
|
||||
tmpfn = tempname() * "." * ext
|
||||
PlotlyJS.savefig(plt.o, tmpfn)
|
||||
write(io, read(open(tmpfn)))
|
||||
end
|
||||
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
|
||||
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
|
||||
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
|
||||
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
|
||||
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = show(io, MIME("text/html"), plt.o)
|
||||
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="svg")
|
||||
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="png")
|
||||
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="pdf")
|
||||
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="eps")
|
||||
|
||||
function write_temp_html(plt::Plot{PlotlyJSBackend})
|
||||
filename = string(tempname(), ".html")
|
||||
|
||||
+99
-88
@@ -1,55 +1,9 @@
|
||||
# Do "using PyPlot: PyCall, LaTeXStrings" without dependency warning:
|
||||
const PyCall = PyPlot.PyCall
|
||||
const LaTeXStrings = PyPlot.LaTeXStrings
|
||||
|
||||
# https://github.com/stevengj/PyPlot.jl
|
||||
|
||||
const _pyplot_attr = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:titlefontfamily, :titlefontsize, :titlefontcolor,
|
||||
:legendfontfamily, :legendfontsize, :legendfontcolor,
|
||||
:tickfontfamily, :tickfontsize, :tickfontcolor,
|
||||
:guidefontfamily, :guidefontsize, :guidefontcolor,
|
||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
||||
:legend, :legendtitle, :colorbar,
|
||||
:marker_z, :line_z, :fill_z,
|
||||
:levels,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
:dpi,
|
||||
:colorbar_title,
|
||||
:stride,
|
||||
:framestyle,
|
||||
:tick_direction,
|
||||
:camera,
|
||||
:contour_labels,
|
||||
])
|
||||
const _pyplot_seriestype = [
|
||||
:path, :steppre, :steppost, :shape, :straightline,
|
||||
:scatter, :hexbin, #:histogram2d, :histogram,
|
||||
# :bar,
|
||||
:heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
const _pyplot_marker = vcat(_allMarkers, :pixel)
|
||||
const _pyplot_scale = [:identity, :ln, :log2, :log10]
|
||||
is_marker_supported(::PyPlotBackend, shape::Shape) = true
|
||||
|
||||
|
||||
@@ -236,26 +190,22 @@ function add_pyfixedformatter(cbar, vals::AVec)
|
||||
cbar[:update_ticks]()
|
||||
end
|
||||
|
||||
@require LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" begin
|
||||
function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
if scale == :log10
|
||||
x -> LaTeXStrings.latexstring("10^{$x}")
|
||||
elseif scale == :log2
|
||||
x -> LaTeXStrings.latexstring("2^{$x}")
|
||||
elseif scale == :ln
|
||||
x -> LaTeXStrings.latexstring("e^{$x}")
|
||||
else
|
||||
string
|
||||
end
|
||||
function labelfunc(scale::Symbol, backend::PyPlotBackend)
|
||||
if scale == :log10
|
||||
x -> LaTeXStrings.latexstring("10^{$x}")
|
||||
elseif scale == :log2
|
||||
x -> LaTeXStrings.latexstring("2^{$x}")
|
||||
elseif scale == :ln
|
||||
x -> LaTeXStrings.latexstring("e^{$x}")
|
||||
else
|
||||
string
|
||||
end
|
||||
end
|
||||
|
||||
@require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" begin
|
||||
function py_mask_nans(z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
function py_mask_nans(z)
|
||||
# pynp["ma"][:masked_invalid](z)))
|
||||
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
|
||||
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -272,17 +222,6 @@ function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
end
|
||||
|
||||
# total hack due to PyPlot bug (see issue #145).
|
||||
# hack: duplicate the color vector when the total rgba fields is the same as the series length
|
||||
function py_color_fix(c, x)
|
||||
if (typeof(c) <: AbstractArray && length(c)*4 == length(x)) ||
|
||||
(typeof(c) <: Tuple && length(x) == 4)
|
||||
vcat(c, c)
|
||||
else
|
||||
c
|
||||
end
|
||||
end
|
||||
|
||||
py_linecolor(series::Series) = py_color(series[:linecolor])
|
||||
py_markercolor(series::Series) = py_color(series[:markercolor])
|
||||
py_markerstrokecolor(series::Series) = py_color(series[:markerstrokecolor])
|
||||
@@ -439,7 +378,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
vmin, vmax = clims = get_clims(sp)
|
||||
|
||||
# Dict to store extra kwargs
|
||||
extrakw = KW(:vmin => vmin, :vmax => vmax)
|
||||
if st == :wireframe
|
||||
extrakw = KW() # vmin, vmax cause an error for wireframe plot
|
||||
else
|
||||
extrakw = KW(:vmin => vmin, :vmax => vmax)
|
||||
end
|
||||
|
||||
# holds references to any python object representing the matplotlib series
|
||||
handles = []
|
||||
@@ -547,7 +490,13 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
else
|
||||
py_color(plot_color(series[:markercolor], series[:markeralpha]))
|
||||
end
|
||||
extrakw[:c] = py_color_fix(markercolor, x)
|
||||
extrakw[:c] = if markercolor isa Array
|
||||
permutedims(hcat([[m...] for m in markercolor]...),[2,1])
|
||||
elseif markercolor isa Tuple
|
||||
reshape([markercolor...], 1, length(markercolor))
|
||||
else
|
||||
error("This case is not handled. Please file an issue.")
|
||||
end
|
||||
xyargs = if st == :bar && !isvertical(series)
|
||||
(y, x)
|
||||
else
|
||||
@@ -555,7 +504,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if isa(series[:markershape], AbstractVector{Shape})
|
||||
# this section will create one scatter per data point to accomodate the
|
||||
# this section will create one scatter per data point to accommodate the
|
||||
# vector of shapes
|
||||
handle = []
|
||||
x,y = xyargs
|
||||
@@ -575,6 +524,68 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
extrakw...
|
||||
))
|
||||
end
|
||||
push!(handles, handle)
|
||||
elseif isa(series[:markershape], AbstractVector{Symbol})
|
||||
handle = []
|
||||
x,y = xyargs
|
||||
shapes = series[:markershape]
|
||||
|
||||
prev_marker = py_marker(_cycle(shapes,1))
|
||||
|
||||
cur_x_list = []
|
||||
cur_y_list = []
|
||||
|
||||
cur_color_list = []
|
||||
cur_scale_list = []
|
||||
|
||||
delete!(extrakw, :c)
|
||||
|
||||
for i=1:length(y)
|
||||
cur_marker = py_marker(_cycle(shapes,i))
|
||||
|
||||
if ( cur_marker == prev_marker )
|
||||
push!(cur_x_list, _cycle(x,i))
|
||||
push!(cur_y_list, _cycle(y,i))
|
||||
|
||||
push!(cur_color_list, _cycle(markercolor, i))
|
||||
push!(cur_scale_list, py_thickness_scale(plt, _cycle(series[:markersize],i) .^ 2))
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
push!(handle, ax[:scatter](cur_x_list, cur_y_list;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = prev_marker,
|
||||
s = cur_scale_list,
|
||||
edgecolors = py_markerstrokecolor(series),
|
||||
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
|
||||
facecolors = cur_color_list,
|
||||
extrakw...
|
||||
))
|
||||
|
||||
cur_x_list = [_cycle(x,i)]
|
||||
cur_y_list = [_cycle(y,i)]
|
||||
|
||||
cur_color_list = [_cycle(markercolor, i)]
|
||||
cur_scale_list = [py_thickness_scale(plt, _cycle(series[:markersize],i) .^ 2)]
|
||||
|
||||
prev_marker = cur_marker
|
||||
end
|
||||
|
||||
if !isempty(cur_color_list)
|
||||
push!(handle, ax[:scatter](cur_x_list, cur_y_list;
|
||||
label = series[:label],
|
||||
zorder = series[:series_plotindex] + 0.5,
|
||||
marker = prev_marker,
|
||||
s = cur_scale_list,
|
||||
edgecolors = py_markerstrokecolor(series),
|
||||
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
|
||||
facecolors = cur_color_list,
|
||||
extrakw...
|
||||
))
|
||||
end
|
||||
|
||||
push!(handles, handle)
|
||||
else
|
||||
# do a normal scatter plot
|
||||
@@ -718,7 +729,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
handle = ax[:imshow](z;
|
||||
zorder = series[:series_plotindex],
|
||||
cmap = py_colormap([:black, :white]),
|
||||
cmap = py_colormap(cgrad([:black, :white])),
|
||||
vmin = 0.0,
|
||||
vmax = 1.0,
|
||||
extent = (xmin, xmax, ymax, ymin)
|
||||
@@ -839,7 +850,7 @@ function py_set_ticks(ax, ticks, letter)
|
||||
if ticks == :none || ticks == nothing || ticks == false
|
||||
kw = KW()
|
||||
for dir in (:top,:bottom,:left,:right)
|
||||
kw[dir] = kw[Symbol(:label,dir)] = "off"
|
||||
kw[dir] = kw[Symbol(:label,dir)] = false
|
||||
end
|
||||
axis[:set_tick_params](;which="both", kw...)
|
||||
return
|
||||
@@ -1064,7 +1075,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
|
||||
# don't show the 0 tick label for the origin framestyle
|
||||
if sp[:framestyle] == :origin && length(ticks) > 1
|
||||
ticks[2][ticks[1] .== 0] = ""
|
||||
ticks[2][ticks[1] .== 0] .= ""
|
||||
end
|
||||
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
|
||||
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
|
||||
@@ -1102,7 +1113,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
else
|
||||
ax[:spines][string(dir)][:set_visible](false)
|
||||
end
|
||||
kw[dir] = kw[Symbol(:label,dir)] = "off"
|
||||
kw[dir] = kw[Symbol(:label,dir)] = false
|
||||
end
|
||||
ax[:xaxis][:set_tick_params](; which="both", kw...)
|
||||
end
|
||||
@@ -1112,7 +1123,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)] = "off"
|
||||
kw[dir] = kw[Symbol(:label,dir)] = false
|
||||
end
|
||||
ax[:yaxis][:set_tick_params](; which="both", kw...)
|
||||
end
|
||||
@@ -1203,7 +1214,7 @@ function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText)
|
||||
color = py_color(val.font.color),
|
||||
horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign),
|
||||
verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign),
|
||||
rotation = val.font.rotation * 180 / π,
|
||||
rotation = val.font.rotation,
|
||||
size = py_thickness_scale(sp.plt, val.font.pointsize),
|
||||
zorder = 999
|
||||
)
|
||||
@@ -1239,12 +1250,12 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
linestyle = py_linestyle(series[:seriestype], get_linestyle(series))
|
||||
)
|
||||
elseif series[:seriestype] in (:path, :straightline)
|
||||
elseif series[:seriestype] in (:path, :straightline, :scatter)
|
||||
PyPlot.plt[:Line2D]((0,1),(0,0),
|
||||
color = py_color(get_linecolor(series, clims), get_linealpha(series)),
|
||||
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
|
||||
linestyle = py_linestyle(:path, get_linestyle(series)),
|
||||
marker = py_marker(series[:markershape]),
|
||||
marker = py_marker(first(series[:markershape])),
|
||||
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
|
||||
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series, clims), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
|
||||
)
|
||||
|
||||
@@ -1,28 +1,6 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
const _unicodeplots_attr = merge_with_base_supported([
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor,
|
||||
:seriesalpha,
|
||||
:linestyle,
|
||||
:markershape,
|
||||
:bins,
|
||||
:title,
|
||||
:guide, :lims,
|
||||
])
|
||||
const _unicodeplots_seriestype = [
|
||||
:path, :scatter, :straightline,
|
||||
# :bar,
|
||||
:shape,
|
||||
:histogram2d,
|
||||
:spy
|
||||
]
|
||||
const _unicodeplots_style = [:auto, :solid]
|
||||
const _unicodeplots_marker = [:none, :auto, :circle]
|
||||
const _unicodeplots_scale = [:identity]
|
||||
|
||||
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warnOnUnsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
|
||||
|
||||
@@ -42,8 +42,14 @@ function write_temp_html(plt::AbstractPlot)
|
||||
end
|
||||
|
||||
function standalone_html_window(plt::AbstractPlot)
|
||||
old = use_local_dependencies[] # save state to restore afterwards
|
||||
# if we open a browser ourself, we can host local files, so
|
||||
# when we have a local plotly downloaded this is the way to go!
|
||||
use_local_dependencies[] = isfile(plotly_local_file_path)
|
||||
filename = write_temp_html(plt)
|
||||
open_browser_window(filename)
|
||||
# restore for other backends
|
||||
use_local_dependencies[] = old
|
||||
end
|
||||
|
||||
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
|
||||
|
||||
+57
-14
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
const P2 = FixedSizeArrays.Vec{2,Float64}
|
||||
const P3 = FixedSizeArrays.Vec{3,Float64}
|
||||
const P2 = StaticArrays.SVector{2,Float64}
|
||||
const P3 = StaticArrays.SVector{3,Float64}
|
||||
|
||||
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
|
||||
@@ -256,8 +256,24 @@ mutable struct Font
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
"Create a Font from a list of unordered features"
|
||||
function font(args...)
|
||||
"""
|
||||
font(args...)
|
||||
Create a Font from a list of features. Values may be specified either as
|
||||
arguments (which are distinguished by type/value) or as keyword arguments.
|
||||
# Arguments
|
||||
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
|
||||
- `pointsize`: Integer. Size of font in points
|
||||
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
|
||||
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
|
||||
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
|
||||
- `color`: Colorant or Symbol
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> font(8)
|
||||
julia> font(family="serif",halign=:center,rotation=45.0)
|
||||
```
|
||||
"""
|
||||
function font(args...;kw...)
|
||||
|
||||
# defaults
|
||||
family = "sans-serif"
|
||||
@@ -301,6 +317,32 @@ function font(args...)
|
||||
end
|
||||
end
|
||||
|
||||
for symbol in keys(kw)
|
||||
if symbol == :family
|
||||
family = kw[:family]
|
||||
elseif symbol == :pointsize
|
||||
pointsize = kw[:pointsize]
|
||||
elseif symbol == :halign
|
||||
halign = kw[:halign]
|
||||
if halign == :center
|
||||
halign = :hcenter
|
||||
end
|
||||
@assert halign in (:hcenter, :left, :right)
|
||||
elseif symbol == :valign
|
||||
valign = kw[:valign]
|
||||
if valign == :center
|
||||
valign = :vcenter
|
||||
end
|
||||
@assert valign in (:vcenter, :top, :bottom)
|
||||
elseif symbol == :rotation
|
||||
rotation = kw[:rotation]
|
||||
elseif symbol == :color
|
||||
color = parse(Colorant, kw[:color])
|
||||
else
|
||||
@warn("Unused font kwarg: $symbol")
|
||||
end
|
||||
end
|
||||
|
||||
Font(family, pointsize, halign, valign, rotation, color)
|
||||
end
|
||||
|
||||
@@ -344,15 +386,16 @@ end
|
||||
PlotText(str) = PlotText(string(str), font())
|
||||
|
||||
"""
|
||||
text(string, args...)
|
||||
text(string, args...; kw...)
|
||||
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations
|
||||
Create a PlotText object wrapping a string with font info, for plot annotations.
|
||||
`args` and `kw` are passed to `font`.
|
||||
"""
|
||||
text(t::PlotText) = t
|
||||
text(t::PlotText, font::Font) = PlotText(t.str, font)
|
||||
text(str::AbstractString, f::Font) = PlotText(str, f)
|
||||
function text(str, args...)
|
||||
PlotText(string(str), font(args...))
|
||||
function text(str, args...;kw...)
|
||||
PlotText(string(str), font(args...;kw...))
|
||||
end
|
||||
|
||||
Base.length(t::PlotText) = length(t.str)
|
||||
@@ -491,7 +534,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
# with a list of custom shapes for each
|
||||
msw,msh = anns.scalefactor
|
||||
msize = Float64[]
|
||||
shapes = Vector{Shape}(length(anns.strs))
|
||||
shapes = Vector{Shape}(undef, length(anns.strs))
|
||||
for i in eachindex(anns.strs)
|
||||
str = _cycle(anns.strs,i)
|
||||
|
||||
@@ -509,7 +552,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
# and then re-scale a copy of baseshape to match the w/h ratio
|
||||
maxscale = max(xscale, yscale)
|
||||
push!(msize, maxscale)
|
||||
baseshape = _cycle(get(anns.baseshape),i)
|
||||
baseshape = _cycle(anns.baseshape, i)
|
||||
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
|
||||
end
|
||||
series[:markershape] = shapes
|
||||
@@ -554,7 +597,7 @@ function process_annotation(sp::Subplot, xs, ys, labs, font = font())
|
||||
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
|
||||
else
|
||||
push!(anns, (x, y, isa(lab, PlotText) ? lab : text(lab, font)))
|
||||
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
|
||||
end
|
||||
end
|
||||
anns
|
||||
@@ -569,7 +612,7 @@ function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol},
|
||||
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
|
||||
else
|
||||
push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font)))
|
||||
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
|
||||
end
|
||||
end
|
||||
anns
|
||||
@@ -736,7 +779,7 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
"create a BezierCurve for plotting"
|
||||
mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
mutable struct BezierCurve{T <: StaticArrays.SVector}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
@@ -750,7 +793,7 @@ function (bc::BezierCurve)(t::Real)
|
||||
end
|
||||
|
||||
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
|
||||
# mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
|
||||
# mean{N,T<:Real}(ps::StaticArrays.SVector{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
|
||||
|
||||
@deprecate curve_points coords
|
||||
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
supported_attrs(::BokehBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:linecolor,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
# :linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
:size,
|
||||
:title,
|
||||
# :window_title,
|
||||
:x,
|
||||
# :xguide,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
:y,
|
||||
# :yguide,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface,
|
||||
# :levels,
|
||||
])
|
||||
supported_types(::BokehBackend) = [:path, :scatter]
|
||||
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::BokehBackend) = [:identity, :ln]
|
||||
is_subplot_supported(::BokehBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
function _initialize_backend(::BokehBackend; kw...)
|
||||
@eval begin
|
||||
@warn("Bokeh is no longer supported... many features will likely be broken.")
|
||||
import Bokeh
|
||||
export Bokeh
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
const _glyphtypes = KW(
|
||||
:circle => :Circle,
|
||||
:rect => :Square,
|
||||
:diamond => :Diamond,
|
||||
:utriangle => :Triangle,
|
||||
:dtriangle => :InvertedTriangle,
|
||||
# :pentagon =>
|
||||
# :hexagon =>
|
||||
# :heptagon =>
|
||||
# :octagon =>
|
||||
:cross => :Cross,
|
||||
:xcross => :X,
|
||||
:star5 => :Asterisk,
|
||||
)
|
||||
|
||||
|
||||
function bokeh_glyph_type(plotattributes::KW)
|
||||
st = plotattributes[:seriestype]
|
||||
mt = plotattributes[:markershape]
|
||||
if st == :scatter && mt == :none
|
||||
mt = :circle
|
||||
end
|
||||
|
||||
# if we have a marker, use that
|
||||
if st == :scatter || mt != :none
|
||||
return _glyphtypes[mt]
|
||||
end
|
||||
|
||||
# otherwise return a line
|
||||
return :Line
|
||||
end
|
||||
|
||||
function get_stroke_vector(linestyle::Symbol)
|
||||
dash = 12
|
||||
dot = 3
|
||||
gap = 2
|
||||
linestyle == :solid && return Int[]
|
||||
linestyle == :dash && return Int[dash, gap]
|
||||
linestyle == :dot && return Int[dot, gap]
|
||||
linestyle == :dashdot && return Int[dash, gap, dot, gap]
|
||||
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
|
||||
error("unsupported linestyle: ", linestyle)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# function _create_plot(pkg::BokehBackend, plotattributes::KW)
|
||||
function _create_backend_figure(plt::Plot{BokehBackend})
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
|
||||
datacolumns = Bokeh.BokehDataSet[]
|
||||
tools = Bokeh.tools()
|
||||
filename = tempname() * ".html"
|
||||
title = plt.attr[:title]
|
||||
w, h = plt.attr[:size]
|
||||
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
|
||||
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
|
||||
# legend = plt.attr[:legend] ? xxxx : nothing
|
||||
legend = nothing
|
||||
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
|
||||
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
|
||||
|
||||
# Plot(bplt, pkg, 0, plotattributes, KW[])
|
||||
end
|
||||
|
||||
|
||||
# function _series_added(::BokehBackend, plt::Plot, plotattributes::KW)
|
||||
function _series_added(plt::Plot{BokehBackend}, series::Series)
|
||||
bdata = Dict{Symbol, Vector}(:x => collect(series.plotattributes[:x]), :y => collect(series.plotattributes[:y]))
|
||||
|
||||
glyph = Bokeh.Bokehjs.Glyph(
|
||||
glyphtype = bokeh_glyph_type(plotattributes),
|
||||
linecolor = webcolor(plotattributes[:linecolor]), # shape's stroke or line color
|
||||
linewidth = plotattributes[:linewidth], # shape's stroke width or line width
|
||||
fillcolor = webcolor(plotattributes[:markercolor]),
|
||||
size = ceil(Int, plotattributes[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
|
||||
dash = get_stroke_vector(plotattributes[:linestyle])
|
||||
)
|
||||
|
||||
legend = nothing # TODO
|
||||
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
|
||||
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot_object(plt::Plot{BokehBackend}, plotattributes::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
# function getxy(plt::Plot{BokehBackend}, i::Int)
|
||||
# series = plt.o.datacolumns[i].data
|
||||
# series[:x], series[:y]
|
||||
# end
|
||||
#
|
||||
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
|
||||
# series = plt.o.datacolumns[i].data
|
||||
# series[:x], series[:y] = xy
|
||||
# plt
|
||||
# end
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
|
||||
# TODO: write a png to io
|
||||
@warn("mime png not implemented")
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
|
||||
Bokeh.showplot(plt.o)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
|
||||
# # TODO: display/show the subplot
|
||||
# end
|
||||
@@ -1,744 +0,0 @@
|
||||
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
|
||||
supported_attrs(::GadflyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
:group, :label, :seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :n, :nc, :nr, :layout, :smooth,
|
||||
:title, :window_title, :show, :size,
|
||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
|
||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
|
||||
:z,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
])
|
||||
supported_types(::GadflyBackend) = [
|
||||
:path,
|
||||
:scatter, :hexbin,
|
||||
:bar,
|
||||
:contour, :shape
|
||||
]
|
||||
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
is_subplot_supported(::GadflyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::GadflyBackend; kw...)
|
||||
@eval begin
|
||||
import Gadfly, Compose
|
||||
export Gadfly, Compose
|
||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# immutable MissingVec <: AbstractVector{Float64} end
|
||||
# Base.size(v::MissingVec) = (1,)
|
||||
# Base.getindex(v::MissingVec, i::Integer) = 0.0
|
||||
|
||||
function createGadflyPlotObject(plotattributes::KW)
|
||||
gplt = Gadfly.Plot()
|
||||
gplt.mapping = Dict()
|
||||
gplt.data_source = Gadfly.DataFrames.DataFrame()
|
||||
# gplt.layers = gplt.layers[1:0]
|
||||
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
|
||||
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(plotattributes[:xguide]),
|
||||
Gadfly.Guide.ylabel(plotattributes[:yguide]),
|
||||
Gadfly.Guide.title(plotattributes[:title])]
|
||||
gplt
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function getLineGeom(plotattributes::KW)
|
||||
st = plotattributes[:seriestype]
|
||||
xbins, ybins = maketuple(plotattributes[:bins])
|
||||
if st == :hexb
|
||||
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
|
||||
elseif st == :histogram2d
|
||||
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
|
||||
elseif st == :histogram
|
||||
Gadfly.Geom.histogram(bincount = xbins,
|
||||
orientation = isvertical(plotattributes) ? :vertical : :horizontal,
|
||||
position = plotattributes[:bar_position] == :stack ? :stack : :dodge)
|
||||
elseif st == :path
|
||||
Gadfly.Geom.path
|
||||
elseif st in (:bar, :sticks)
|
||||
Gadfly.Geom.bar
|
||||
elseif st == :steppost
|
||||
Gadfly.Geom.step
|
||||
elseif st == :steppre
|
||||
Gadfly.Geom.step(direction = :vh)
|
||||
elseif st == :hline
|
||||
Gadfly.Geom.hline
|
||||
elseif st == :vline
|
||||
Gadfly.Geom.vline
|
||||
elseif st == :contour
|
||||
Gadfly.Geom.contour(levels = plotattributes[:levels])
|
||||
# elseif st == :shape
|
||||
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
||||
else
|
||||
nothing
|
||||
end
|
||||
end
|
||||
|
||||
function get_extra_theme_args(plotattributes::KW, k::Symbol)
|
||||
# gracefully handles old Gadfly versions
|
||||
extra_theme_args = KW()
|
||||
try
|
||||
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(plotattributes[k])
|
||||
catch err
|
||||
if string(err) == "UndefVarError(:get_stroke_vector)"
|
||||
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
|
||||
else
|
||||
rethrow()
|
||||
end
|
||||
end
|
||||
extra_theme_args
|
||||
end
|
||||
|
||||
function getGadflyLineTheme(plotattributes::KW)
|
||||
st = plotattributes[:seriestype]
|
||||
lc = convertColor(getColor(plotattributes[:linecolor]), plotattributes[:linealpha])
|
||||
fc = convertColor(getColor(plotattributes[:fillcolor]), plotattributes[:fillalpha])
|
||||
|
||||
Gadfly.Theme(;
|
||||
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
|
||||
line_width = (st == :sticks ? 1 : plotattributes[:linewidth]) * Gadfly.px,
|
||||
# line_style = Gadfly.get_stroke_vector(plotattributes[:linestyle]),
|
||||
lowlight_color = x->RGB(fc), # fill/ribbon
|
||||
lowlight_opacity = alpha(fc), # fill/ribbon
|
||||
bar_highlight = RGB(lc), # bars
|
||||
get_extra_theme_args(plotattributes, :linestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
# add a line as a new layer
|
||||
function addGadflyLine!(plt::Plot, numlayers::Int, plotattributes::KW, geoms...)
|
||||
gplt = getGadflyContext(plt)
|
||||
gfargs = vcat(geoms..., getGadflyLineTheme(plotattributes))
|
||||
kwargs = KW()
|
||||
st = plotattributes[:seriestype]
|
||||
|
||||
# add a fill?
|
||||
if plotattributes[:fillrange] != nothing && st != :contour
|
||||
fillmin, fillmax = map(makevec, maketuple(plotattributes[:fillrange]))
|
||||
nmin, nmax = length(fillmin), length(fillmax)
|
||||
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
|
||||
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
|
||||
push!(gfargs, Gadfly.Geom.ribbon)
|
||||
end
|
||||
|
||||
if st in (:hline, :vline)
|
||||
kwargs[st == :hline ? :yintercept : :xintercept] = plotattributes[:y]
|
||||
|
||||
else
|
||||
if st == :sticks
|
||||
w = 0.01 * mean(diff(plotattributes[:x]))
|
||||
kwargs[:xmin] = plotattributes[:x] - w
|
||||
kwargs[:xmax] = plotattributes[:x] + w
|
||||
elseif st == :contour
|
||||
kwargs[:z] = plotattributes[:z].surf
|
||||
addGadflyContColorScale(plt, plotattributes[:linecolor])
|
||||
end
|
||||
|
||||
kwargs[:x] = plotattributes[st == :histogram ? :y : :x]
|
||||
kwargs[:y] = plotattributes[:y]
|
||||
|
||||
end
|
||||
|
||||
# # add the layer
|
||||
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
get_shape(sym::Symbol) = _shapes[sym]
|
||||
get_shape(shape::Shape) = shape
|
||||
|
||||
# extract the underlying ShapeGeometry object(s)
|
||||
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
|
||||
getMarkerGeom(other) = gadflyshape(get_shape(other))
|
||||
|
||||
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
|
||||
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
|
||||
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
|
||||
function getMarkerGeom(plotattributes::KW)
|
||||
if plotattributes[:seriestype] == :shape
|
||||
Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
||||
else
|
||||
getMarkerGeom(plotattributes[:markershape])
|
||||
end
|
||||
end
|
||||
|
||||
function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
|
||||
c = getColor(plotattributes[:markercolor])
|
||||
α = plotattributes[:markeralpha]
|
||||
if α != nothing
|
||||
c = RGBA(RGB(c), α)
|
||||
end
|
||||
|
||||
ms = plotattributes[:markersize]
|
||||
ms = if typeof(ms) <: AVec
|
||||
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
|
||||
mean(ms) * Gadfly.px
|
||||
else
|
||||
ms * Gadfly.px
|
||||
end
|
||||
|
||||
Gadfly.Theme(;
|
||||
default_color = c,
|
||||
default_point_size = ms,
|
||||
discrete_highlight_color = c -> RGB(getColor(plotattributes[:markerstrokecolor])),
|
||||
highlight_width = plotattributes[:markerstrokewidth] * Gadfly.px,
|
||||
line_width = plotattributes[:markerstrokewidth] * Gadfly.px,
|
||||
# get_extra_theme_args(plotattributes, :markerstrokestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
|
||||
plt.attr[:colorbar] == :none && return
|
||||
if !isa(c, ColorGradient)
|
||||
c = default_gradient()
|
||||
end
|
||||
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
|
||||
end
|
||||
|
||||
function addGadflyMarker!(plt::Plot, numlayers::Int, plotattributes::KW, attr::KW, geoms...)
|
||||
gfargs = vcat(geoms..., getGadflyMarkerTheme(plotattributes, attr), getMarkerGeom(plotattributes))
|
||||
kwargs = KW()
|
||||
|
||||
# handle continuous color scales for the markers
|
||||
zcolor = plotattributes[:marker_z]
|
||||
if zcolor != nothing && typeof(zcolor) <: AVec
|
||||
kwargs[:color] = zcolor
|
||||
addGadflyContColorScale(plt, plotattributes[:markercolor])
|
||||
end
|
||||
|
||||
Gadfly.layer(gfargs...; x = plotattributes[:x], y = plotattributes[:y], order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function addToGadflyLegend(plt::Plot, plotattributes::KW)
|
||||
if plt.attr[:legend] != :none && plotattributes[:label] != ""
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add the legend if needed
|
||||
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
|
||||
pushfirst!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
|
||||
end
|
||||
|
||||
# now add the series to the legend
|
||||
for guide in gplt.guides
|
||||
if isa(guide, Gadfly.Guide.ManualColorKey)
|
||||
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
|
||||
# since gadfly will call unique(colors), but doesn't also merge the rows that match
|
||||
# Should ensure from this side that colors which are the same are merged together
|
||||
|
||||
c = getColor(plotattributes[plotattributes[:markershape] == :none ? :linecolor : :markercolor])
|
||||
foundit = false
|
||||
|
||||
# extend the label if we found this color
|
||||
for i in 1:length(guide.colors)
|
||||
if RGB(c) == guide.colors[i]
|
||||
guide.labels[i] *= ", " * plotattributes[:label]
|
||||
foundit = true
|
||||
end
|
||||
end
|
||||
|
||||
# didn't find the color, so add a new entry into the legend
|
||||
if !foundit
|
||||
push!(guide.labels, plotattributes[:label])
|
||||
push!(guide.colors, c)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
|
||||
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
|
||||
|
||||
|
||||
function addGadflySeries!(plt::Plot, plotattributes::KW)
|
||||
layers = Gadfly.Layer[]
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add a regression line?
|
||||
# TODO: make more flexible
|
||||
smooth = getGadflySmoothing(plotattributes[:smooth])
|
||||
|
||||
# lines
|
||||
geom = getLineGeom(plotattributes)
|
||||
if geom != nothing
|
||||
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), plotattributes, geom, smooth...))
|
||||
smooth = Any[] # don't add a regression for markers too
|
||||
end
|
||||
|
||||
# special handling for ohlc and scatter
|
||||
st = plotattributes[:seriestype]
|
||||
# if st == :ohlc
|
||||
# error("Haven't re-implemented after refactoring")
|
||||
if st in (:histogram2d, :hexbin) && (isa(plotattributes[:fillcolor], ColorGradient) || isa(plotattributes[:fillcolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(plotattributes[:fillcolor], p))))
|
||||
elseif st == :scatter && plotattributes[:markershape] == :none
|
||||
plotattributes[:markershape] = :circle
|
||||
end
|
||||
|
||||
# markers
|
||||
if plotattributes[:markershape] != :none || st == :shape
|
||||
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), plotattributes, plt.attr, smooth...))
|
||||
end
|
||||
|
||||
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, plotattributes)
|
||||
|
||||
# now save the layers that apply to this series
|
||||
plotattributes[:gadflylayers] = layers
|
||||
prepend!(gplt.layers, layers)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
|
||||
|
||||
# # colorgroup
|
||||
# z = plotattributes[:z]
|
||||
|
||||
# # handle line segments of different colors
|
||||
# cscheme = plotattributes[:linecolor]
|
||||
# if isa(cscheme, ColorVector)
|
||||
# # create a color scale, and set the color group to the index of the color
|
||||
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
|
||||
|
||||
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
|
||||
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
|
||||
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
|
||||
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(plotattributes[:y])]
|
||||
# cs = collect(repeat(csindices', 2, 1))[1:end-1]
|
||||
# grp = collect(repeat((1:length(plotattributes[:y]))', 2, 1))[1:end-1]
|
||||
# plotattributes[:x], plotattributes[:y] = map(createSegments, (plotattributes[:x], plotattributes[:y]))
|
||||
# colorgroup = [(:linecolor, cs), (:group, grp)]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
|
||||
ticks == :auto && return
|
||||
|
||||
# remove the ticks?
|
||||
if ticks in (:none, false, nothing)
|
||||
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
end
|
||||
|
||||
ttype = ticksType(ticks)
|
||||
|
||||
# just the values... put ticks here, but use standard labels
|
||||
if ttype == :ticks
|
||||
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
|
||||
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
|
||||
|
||||
# set the ticks and the labels
|
||||
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
|
||||
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
|
||||
elseif ttype == :ticks_and_labels
|
||||
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
|
||||
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
|
||||
|
||||
# # TODO add xtick_label function (given tick, return label??)
|
||||
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
|
||||
# filterGadflyScale(gplt, isx)
|
||||
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
|
||||
# labelmap = Dict(zip(ticks...))
|
||||
# labelfunc = val -> labelmap[val]
|
||||
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
|
||||
|
||||
filterGadflyScale(gplt, isx)
|
||||
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
|
||||
labelmap = Dict(zip(ticks...))
|
||||
labelfunc = val -> labelmap[val]
|
||||
push!(gplt.scales, gfunc(labels = labelfunc))
|
||||
|
||||
else
|
||||
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
|
||||
end
|
||||
end
|
||||
|
||||
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
|
||||
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
|
||||
|
||||
|
||||
function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
|
||||
scalekey = isx ? :xscale : :yscale
|
||||
hasScaleKey = haskey(plotattributes, scalekey)
|
||||
if hasScaleKey
|
||||
scale = plotattributes[scalekey]
|
||||
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
|
||||
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
|
||||
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
|
||||
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
|
||||
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
|
||||
end
|
||||
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
|
||||
end
|
||||
|
||||
|
||||
function addGadflyLimitsScale(gplt, plotattributes::KW, isx::Bool)
|
||||
gfunc, hasScaleKey, func = getGadflyScaleFunction(plotattributes, isx)
|
||||
|
||||
# do we want to add min/max limits for the axis?
|
||||
limsym = isx ? :xlims : :ylims
|
||||
limargs = Any[]
|
||||
|
||||
# map :auto to nothing, otherwise add to limargs
|
||||
lims = get(plotattributes, limsym, :auto)
|
||||
if lims == :auto
|
||||
lims = nothing
|
||||
else
|
||||
if limsType(lims) == :limits
|
||||
push!(limargs, (:minvalue, min(lims...)))
|
||||
push!(limargs, (:maxvalue, max(lims...)))
|
||||
else
|
||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
||||
end
|
||||
end
|
||||
|
||||
# replace any current scales with this one
|
||||
if hasScaleKey || !isempty(limargs)
|
||||
filterGadflyScale(gplt, isx)
|
||||
push!(gplt.scales, gfunc(; limargs...))
|
||||
end
|
||||
|
||||
lims, func
|
||||
end
|
||||
|
||||
function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yfunc)
|
||||
if isa(gplt.coord, Gadfly.Coord.Cartesian)
|
||||
gplt.coord = Gadfly.Coord.cartesian(
|
||||
gplt.coord.xvars,
|
||||
gplt.coord.yvars;
|
||||
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
|
||||
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
|
||||
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
|
||||
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
|
||||
xflip = get(plotattributes, :xflip, gplt.coord.xflip),
|
||||
yflip = get(plotattributes, :yflip, gplt.coord.yflip),
|
||||
fixed = gplt.coord.fixed,
|
||||
aspect_ratio = gplt.coord.aspect_ratio,
|
||||
raster = gplt.coord.raster
|
||||
)
|
||||
else
|
||||
gplt.coord = Gadfly.Coord.Cartesian(
|
||||
xflip = get(plotattributes, :xflip, false),
|
||||
yflip = get(plotattributes, :yflip, false)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function findGuideAndSet(gplt, t::DataType, args...; kw...)
|
||||
for (i,guide) in enumerate(gplt.guides)
|
||||
if isa(guide, t)
|
||||
gplt.guides[i] = t(args...; kw...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function updateGadflyGuides(plt::Plot, plotattributes::KW)
|
||||
gplt = getGadflyContext(plt)
|
||||
haskey(plotattributes, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(plotattributes[:title]))
|
||||
haskey(plotattributes, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(plotattributes[:xguide]))
|
||||
haskey(plotattributes, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(plotattributes[:yguide]))
|
||||
|
||||
xlims, xfunc = addGadflyLimitsScale(gplt, plotattributes, true)
|
||||
ylims, yfunc = addGadflyLimitsScale(gplt, plotattributes, false)
|
||||
|
||||
ticks = get(plotattributes, :xticks, :auto)
|
||||
if ticks == :none
|
||||
_remove_axis(plt, true)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, true)
|
||||
end
|
||||
ticks = get(plotattributes, :yticks, :auto)
|
||||
if ticks == :none
|
||||
_remove_axis(plt, false)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, false)
|
||||
end
|
||||
|
||||
updateGadflyAxisFlips(gplt, plotattributes, xlims, ylims, xfunc, yfunc)
|
||||
end
|
||||
|
||||
function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
|
||||
kwargs = KW()
|
||||
|
||||
# colors
|
||||
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
|
||||
map(s -> getColor(plotattributes[s]), (
|
||||
:background_color_inside,
|
||||
:foreground_color_grid,
|
||||
:foreground_color_text,
|
||||
:foreground_color_guide,
|
||||
:foreground_color_legend
|
||||
))
|
||||
|
||||
# # hide the legend?
|
||||
leg = plotattributes[plotattributes[:legend] == :none ? :colorbar : :legend]
|
||||
if leg != :best
|
||||
kwargs[:key_position] = leg == :inside ? :right : leg
|
||||
end
|
||||
|
||||
if !get(plotattributes, :grid, true)
|
||||
kwargs[:grid_color] = gridcolor
|
||||
end
|
||||
|
||||
# fonts
|
||||
tfont, gfont, lfont = plotattributes[:tickfont], plotattributes[:guidefont], plotattributes[:legendfont]
|
||||
|
||||
getGadflyContext(plt).theme = Gadfly.Theme(;
|
||||
background_color = insidecolor,
|
||||
minor_label_color = textcolor,
|
||||
minor_label_font = tfont.family,
|
||||
minor_label_font_size = tfont.pointsize * Gadfly.pt,
|
||||
major_label_color = guidecolor,
|
||||
major_label_font = gfont.family,
|
||||
major_label_font_size = gfont.pointsize * Gadfly.pt,
|
||||
key_title_color = guidecolor,
|
||||
key_title_font = gfont.family,
|
||||
key_title_font_size = gfont.pointsize * Gadfly.pt,
|
||||
key_label_color = legendcolor,
|
||||
key_label_font = lfont.family,
|
||||
key_label_font_size = lfont.pointsize * Gadfly.pt,
|
||||
plot_padding = 1 * Gadfly.mm,
|
||||
kwargs...
|
||||
)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function createGadflyAnnotationObject(x, y, val::AbstractString)
|
||||
Gadfly.Guide.annotation(Compose.compose(
|
||||
Compose.context(),
|
||||
Compose.text(x, y, val)
|
||||
))
|
||||
end
|
||||
|
||||
function createGadflyAnnotationObject(x, y, txt::PlotText)
|
||||
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
|
||||
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
|
||||
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
|
||||
Gadfly.Guide.annotation(Compose.compose(
|
||||
Compose.context(),
|
||||
Compose.text(x, y, txt.str, halign, valign, rotations...),
|
||||
Compose.font(string(txt.font.family)),
|
||||
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
|
||||
Compose.stroke(txt.font.color),
|
||||
Compose.fill(txt.font.color)
|
||||
))
|
||||
end
|
||||
|
||||
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
# function _create_plot(pkg::GadflyBackend, plotattributes::KW)
|
||||
# gplt = createGadflyPlotObject(plotattributes)
|
||||
# Plot(gplt, pkg, 0, plotattributes, KW[])
|
||||
# end
|
||||
function _create_backend_figure(plt::Plot{GadflyBackend})
|
||||
createGadflyPlotObject(plt.attr)
|
||||
end
|
||||
|
||||
|
||||
# plot one data series
|
||||
# function _series_added(::GadflyBackend, plt::Plot, plotattributes::KW)
|
||||
function _series_added(plt::Plot{GadflyBackend}, series::Series)
|
||||
# first clear out the temporary layer
|
||||
gplt = getGadflyContext(plt)
|
||||
if gplt.layers[1].geom.tag == :remove
|
||||
gplt.layers = gplt.layers[2:end]
|
||||
end
|
||||
|
||||
addGadflySeries!(plt, series.plotattributes)
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{GadflyBackend}, plotattributes::KW)
|
||||
updateGadflyGuides(plt, plotattributes)
|
||||
updateGadflyPlotTheme(plt, plotattributes)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
# TODO: need to save all the layer indices which apply to this series
|
||||
function getGadflyMappings(plt::Plot, i::Integer)
|
||||
@assert i > 0 && i <= plt.n
|
||||
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
|
||||
end
|
||||
|
||||
function getxy(plt::Plot{GadflyBackend}, i::Integer)
|
||||
mapping = getGadflyMappings(plt, i)[1]
|
||||
mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
for mapping in getGadflyMappings(plt, i)
|
||||
mapping[:x], mapping[:y] = xy
|
||||
end
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# # create the underlying object (each backend will do this differently)
|
||||
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
|
||||
# isbefore && return false # wait until after plotting to create the subplots
|
||||
# subplt.o = nothing
|
||||
# true
|
||||
# end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
|
||||
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
|
||||
|
||||
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
|
||||
# function buildGadflySubplotContext(subplt::Subplot)
|
||||
# rows = Any[]
|
||||
# row = Any[]
|
||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
||||
#
|
||||
# # add the Plot object to the row
|
||||
# push!(row, getGadflyContext(subplt.plts[i]))
|
||||
#
|
||||
# # add the row
|
||||
# if c == ncols(subplt.layout, r)
|
||||
# push!(rows, Gadfly.hstack(row...))
|
||||
# row = Any[]
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # stack the rows
|
||||
# Gadfly.vstack(rows...)
|
||||
# end
|
||||
|
||||
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
|
||||
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
|
||||
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
|
||||
gplt = getGadflyContext(plt)
|
||||
setGadflyDisplaySize(plt)
|
||||
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
|
||||
end
|
||||
|
||||
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
|
||||
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
|
||||
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
|
||||
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
|
||||
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
|
||||
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
|
||||
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
|
||||
|
||||
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
|
||||
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
|
||||
func = getGadflyWriteFunc($mime())
|
||||
doshow(io, func, plt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
|
||||
setGadflyDisplaySize(plt.attr[:size]...)
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
|
||||
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
|
||||
# ctx = buildGadflySubplotContext(subplt)
|
||||
#
|
||||
# # taken from Gadfly since I couldn't figure out how to do it directly
|
||||
#
|
||||
# filename = string(Gadfly.tempname(), ".html")
|
||||
# output = open(filename, "w")
|
||||
#
|
||||
# plot_output = IOBuffer()
|
||||
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
|
||||
# Compose.default_graphic_height, false), ctx)
|
||||
# plotsvg = takebuf_string(plot_output)
|
||||
#
|
||||
# write(output,
|
||||
# """
|
||||
# <!DOCTYPE html>
|
||||
# <html>
|
||||
# <head>
|
||||
# <title>Gadfly Plot</title>
|
||||
# <meta charset="utf-8">
|
||||
# </head>
|
||||
# <body>
|
||||
# <script charset="utf-8">
|
||||
# $(readall(Compose.snapsvgjs))
|
||||
# </script>
|
||||
# <script charset="utf-8">
|
||||
# $(readall(Gadfly.gadflyjs))
|
||||
# </script>
|
||||
# $(plotsvg)
|
||||
# </body>
|
||||
# </html>
|
||||
# """)
|
||||
# close(output)
|
||||
# Gadfly.open_file(filename)
|
||||
# end
|
||||
@@ -1,93 +0,0 @@
|
||||
|
||||
|
||||
# Geometry which displays arbitrary shapes at given (x, y) positions.
|
||||
# note: vertices is a list of shapes
|
||||
struct ShapeGeometry <: Gadfly.GeometryElement
|
||||
vertices::AbstractVector #{Tuple{Float64,Float64}}
|
||||
tag::Symbol
|
||||
|
||||
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
|
||||
new(shape, tag)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: add for PR
|
||||
# const shape = ShapeGeometry
|
||||
|
||||
|
||||
function Gadfly.element_aesthetics(::ShapeGeometry)
|
||||
[:x, :y, :size, :color]
|
||||
end
|
||||
|
||||
|
||||
# Generate a form for a shape geometry.
|
||||
#
|
||||
# Args:
|
||||
# geom: shape geometry.
|
||||
# theme: the plot's theme.
|
||||
# aes: aesthetics.
|
||||
#
|
||||
# Returns:
|
||||
# A compose Form.
|
||||
#
|
||||
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
|
||||
|
||||
# TODO: add for PR
|
||||
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
|
||||
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
|
||||
# element_aesthetics(geom)...)
|
||||
|
||||
default_aes = Gadfly.Aesthetics()
|
||||
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
|
||||
default_aes.size = Compose.Measure[theme.default_point_size]
|
||||
aes = Gadfly.inherit(aes, default_aes)
|
||||
|
||||
lw_hover_scale = 10
|
||||
lw_ratio = theme.line_width / aes.size[1]
|
||||
|
||||
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
|
||||
|
||||
ctx = Compose.compose!(
|
||||
Compose.context(),
|
||||
make_polygon(geom, aes.x, aes.y, aes.size),
|
||||
Compose.fill(aes.color),
|
||||
Compose.linewidth(theme.highlight_width))
|
||||
|
||||
if aes.color_key_continuous != nothing && aes.color_key_continuous
|
||||
Compose.compose!(ctx,
|
||||
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
|
||||
else
|
||||
Compose.compose!(ctx,
|
||||
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
|
||||
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
|
||||
for c in aes.color]))
|
||||
end
|
||||
|
||||
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
|
||||
end
|
||||
|
||||
function gadflyshape(sv::Shape)
|
||||
ShapeGeometry(Any[vertices(sv)])
|
||||
end
|
||||
|
||||
function gadflyshape(sv::AVec{Shape})
|
||||
ShapeGeometry(Any[vertices(s) for s in sv])
|
||||
end
|
||||
|
||||
|
||||
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
|
||||
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
|
||||
n = max(length(xs), length(ys), length(rs))
|
||||
T = Tuple{Compose.Measure, Compose.Measure}
|
||||
polys = Array(Vector{T}, n)
|
||||
for i in 1:n
|
||||
x = Compose.x_measure(xs[mod1(i, length(xs))])
|
||||
y = Compose.y_measure(ys[mod1(i, length(ys))])
|
||||
r = rs[mod1(i, length(rs))]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
|
||||
end
|
||||
Gadfly.polygon(polys, geom.tag)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
@@ -1,186 +0,0 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
supported_attrs(::ImmerseBackend) = supported_attrs(GadflyBackend())
|
||||
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
|
||||
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
|
||||
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
|
||||
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
|
||||
is_subplot_supported(::ImmerseBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::ImmerseBackend; kw...)
|
||||
@eval begin
|
||||
import Immerse, Gadfly, Compose, Gtk
|
||||
export Immerse, Gadfly, Compose, Gtk
|
||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
function createImmerseFigure(plotattributes::KW)
|
||||
w,h = plotattributes[:size]
|
||||
figidx = Immerse.figure(; name = plotattributes[:window_title], width = w, height = h)
|
||||
Immerse.Figure(figidx)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
# function _create_plot(pkg::ImmerseBackend, plotattributes::KW)
|
||||
# # create the underlying Gadfly.Plot object
|
||||
# gplt = createGadflyPlotObject(plotattributes)
|
||||
#
|
||||
# # save both the Immerse.Figure and the Gadfly.Plot
|
||||
# Plot((nothing,gplt), pkg, 0, plotattributes, KW[])
|
||||
# end
|
||||
function _create_backend_figure(plt::Plot{ImmerseBackend})
|
||||
(nothing, createGadflyPlotObject(plt.attr))
|
||||
end
|
||||
|
||||
|
||||
# # plot one data series
|
||||
# function _series_added(::ImmerseBackend, plt::Plot, plotattributes::KW)
|
||||
# addGadflySeries!(plt, plotattributes)
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# plt
|
||||
# end
|
||||
|
||||
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
|
||||
addGadflySeries!(plt, series.plotattributes)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{ImmerseBackend}, plotattributes::KW)
|
||||
updateGadflyGuides(plt, plotattributes)
|
||||
updateGadflyPlotTheme(plt, plotattributes)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
|
||||
mapping = getGadflyMappings(plt, i)[1]
|
||||
mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
for mapping in getGadflyMappings(plt, i)
|
||||
mapping[:x], mapping[:y] = xy
|
||||
end
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
|
||||
# return false
|
||||
# # isbefore && return false
|
||||
# end
|
||||
#
|
||||
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
|
||||
# # create the Gtk window with vertical box vsep
|
||||
# plotattributes = getattr(subplt,1)
|
||||
# w,h = plotattributes[:size]
|
||||
# vsep = Gtk.GtkBoxLeaf(:v)
|
||||
# win = Gtk.GtkWindowLeaf(vsep, plotattributes[:window_title], w, h)
|
||||
#
|
||||
# figindices = []
|
||||
# row = Gtk.GtkBoxLeaf(:h)
|
||||
# push!(vsep, row)
|
||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
||||
# plt = subplt.plts[i]
|
||||
#
|
||||
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
|
||||
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
|
||||
#
|
||||
# # add the plot's box to the row
|
||||
# push!(row, box)
|
||||
#
|
||||
# # create the figure and store the index returned for destruction later
|
||||
# figidx = Immerse.figure(canvas)
|
||||
# push!(figindices, figidx)
|
||||
#
|
||||
# fig = Immerse.figure(figidx)
|
||||
# plt.o = (fig, plt.o[2])
|
||||
#
|
||||
# # add the row
|
||||
# if c == ncols(subplt.layout, r)
|
||||
# row = Gtk.GtkBoxLeaf(:h)
|
||||
# push!(vsep, row)
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# # destructor... clean up plots
|
||||
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
|
||||
#
|
||||
# subplt.o = win
|
||||
# true
|
||||
# end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
|
||||
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
|
||||
|
||||
fig, gplt = plt.o
|
||||
if fig == nothing
|
||||
fig = createImmerseFigure(plt.attr)
|
||||
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
|
||||
plt.o = (fig, gplt)
|
||||
end
|
||||
|
||||
Immerse.figure(fig.figno; displayfig = false)
|
||||
display(gplt)
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
|
||||
#
|
||||
# # if we haven't created the window yet, do it
|
||||
# if subplt.o == nothing
|
||||
# showSubplotObject(subplt)
|
||||
# end
|
||||
#
|
||||
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
|
||||
# for plt in subplt.plts
|
||||
# fig, gplt = plt.o
|
||||
# Immerse.figure(fig.figno; displayfig = false)
|
||||
# display(gplt)
|
||||
# end
|
||||
#
|
||||
# # o is the window... show it
|
||||
# showall(subplt.o)
|
||||
# end
|
||||
@@ -1,308 +0,0 @@
|
||||
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
|
||||
supported_attrs(::QwtBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:linecolor,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:bins,
|
||||
:pos,
|
||||
:title,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale,
|
||||
])
|
||||
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
|
||||
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supported_scales(::QwtBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::QwtBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
function _initialize_backend(::QwtBackend; kw...)
|
||||
@eval begin
|
||||
@warn("Qwt is no longer supported... many features will likely be broken.")
|
||||
import Qwt
|
||||
export Qwt
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
const _qwtAliases = KW(
|
||||
:bins => :heatmap_n,
|
||||
:fillrange => :fillto,
|
||||
:linewidth => :width,
|
||||
:markershape => :marker,
|
||||
:hexbin => :heatmap,
|
||||
:path => :line,
|
||||
:steppost => :step,
|
||||
:steppre => :stepinverted,
|
||||
:star5 => :star1,
|
||||
:star8 => :star2,
|
||||
)
|
||||
|
||||
function fixcolors(plotattributes::KW)
|
||||
for (k,v) in plotattributes
|
||||
if typeof(v) <: ColorScheme
|
||||
plotattributes[k] = getColor(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function replaceQwtAliases(plotattributes, s)
|
||||
if haskey(_qwtAliases, plotattributes[s])
|
||||
plotattributes[s] = _qwtAliases[plotattributes[s]]
|
||||
end
|
||||
end
|
||||
|
||||
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
||||
plotattributes = KW(kw)
|
||||
st = plotattributes[:seriestype]
|
||||
if st == :scatter
|
||||
plotattributes[:seriestype] = :none
|
||||
if plotattributes[:markershape] == :none
|
||||
plotattributes[:markershape] = :circle
|
||||
end
|
||||
|
||||
elseif st in (:hline, :vline)
|
||||
addLineMarker(plt, plotattributes)
|
||||
plotattributes[:seriestype] = :none
|
||||
plotattributes[:markershape] = :circle
|
||||
plotattributes[:markersize] = 1
|
||||
if st == :vline
|
||||
plotattributes[:x], plotattributes[:y] = plotattributes[:y], plotattributes[:x]
|
||||
end
|
||||
|
||||
elseif !iscreating && st == :bar
|
||||
plotattributes = barHack(; kw...)
|
||||
elseif !iscreating && st == :histogram
|
||||
plotattributes = barHack(; histogramHack(; kw...)...)
|
||||
end
|
||||
|
||||
replaceQwtAliases(plotattributes, :seriestype)
|
||||
replaceQwtAliases(plotattributes, :markershape)
|
||||
|
||||
for k in keys(plotattributes)
|
||||
if haskey(_qwtAliases, k)
|
||||
plotattributes[_qwtAliases[k]] = plotattributes[k]
|
||||
end
|
||||
end
|
||||
|
||||
plotattributes[:x] = collect(plotattributes[:x])
|
||||
plotattributes[:y] = collect(plotattributes[:y])
|
||||
|
||||
plotattributes
|
||||
end
|
||||
|
||||
# function _create_plot(pkg::QwtBackend, plotattributes::KW)
|
||||
function _create_backend_figure(plt::Plot{QwtBackend})
|
||||
fixcolors(plt.attr)
|
||||
dumpdict(plt.attr,"\n\n!!! plot")
|
||||
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
|
||||
# plt = Plot(o, pkg, 0, plotattributes, KW[])
|
||||
# plt
|
||||
end
|
||||
|
||||
# function _series_added(::QwtBackend, plt::Plot, plotattributes::KW)
|
||||
function _series_added(plt::Plot{QwtBackend}, series::Series)
|
||||
plotattributes = adjustQwtKeywords(plt, false; series.plotattributes...)
|
||||
fixcolors(plotattributes)
|
||||
dumpdict(plotattributes,"\n\n!!! plot!")
|
||||
Qwt.oplot(plt.o; plotattributes...)
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function updateLimsAndTicks(plt::Plot{QwtBackend}, plotattributes::KW, isx::Bool)
|
||||
lims = get(plotattributes, isx ? :xlims : :ylims, nothing)
|
||||
ticks = get(plotattributes, isx ? :xticks : :yticks, nothing)
|
||||
w = plt.o.widget
|
||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
||||
|
||||
if typeof(lims) <: Union{Tuple,AVec} && length(lims) == 2
|
||||
if isx
|
||||
plt.o.autoscale_x = false
|
||||
else
|
||||
plt.o.autoscale_y = false
|
||||
end
|
||||
w[:setAxisScale](axisid, lims...)
|
||||
end
|
||||
|
||||
if typeof(ticks) <: AbstractRange
|
||||
if isx
|
||||
plt.o.autoscale_x = false
|
||||
else
|
||||
plt.o.autoscale_y = false
|
||||
end
|
||||
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
|
||||
elseif !(ticks in (nothing, :none, :auto))
|
||||
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
|
||||
end
|
||||
|
||||
# change the scale
|
||||
scalesym = isx ? :xscale : :yscale
|
||||
if haskey(plotattributes, scalesym)
|
||||
scaletype = plotattributes[scalesym]
|
||||
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
|
||||
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
|
||||
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
|
||||
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
|
||||
scaletype in supported_scales() || @warn("Unsupported scale type: ", scaletype)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_object(plt::Plot{QwtBackend}, plotattributes::KW)
|
||||
haskey(plotattributes, :title) && Qwt.title(plt.o, plotattributes[:title])
|
||||
haskey(plotattributes, :xguide) && Qwt.xlabel(plt.o, plotattributes[:xguide])
|
||||
haskey(plotattributes, :yguide) && Qwt.ylabel(plt.o, plotattributes[:yguide])
|
||||
updateLimsAndTicks(plt, plotattributes, true)
|
||||
updateLimsAndTicks(plt, plotattributes, false)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, plotattributes::KW)
|
||||
haskey(plotattributes, :size) && Qwt.resizewidget(plt.o, plotattributes[:size]...)
|
||||
haskey(plotattributes, :pos) && Qwt.movewidget(plt.o, plotattributes[:pos]...)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
|
||||
function addLineMarker(plt::Plot{QwtBackend}, plotattributes::KW)
|
||||
for yi in plotattributes[:y]
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
ishorizontal = (plotattributes[:seriestype] == :hline)
|
||||
marker[:setLineStyle](ishorizontal ? 1 : 2)
|
||||
marker[ishorizontal ? :setYValue : :setXValue](yi)
|
||||
qcolor = Qwt.convertRGBToQColor(getColor(plotattributes[:linecolor]))
|
||||
linestyle = plt.o.widget[:getLineStyle](string(plotattributes[:linestyle]))
|
||||
marker[:setLinePen](Qwt.QT.QPen(qcolor, plotattributes[:linewidth], linestyle))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
# marker[:setValue](x, y)
|
||||
# marker[:setLabel](Qwt.QWT.QwtText(val))
|
||||
# marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
marker[:setValue](x, y)
|
||||
qwttext = Qwt.QWT.QwtText(val.str)
|
||||
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
|
||||
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
|
||||
marker[:setLabel](qwttext)
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
marker[:setValue](x, y)
|
||||
marker[:setLabel](Qwt.QWT.QwtText(val))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
createQwtAnnotation(plt, ann...)
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function getxy(plt::Plot{QwtBackend}, i::Int)
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y
|
||||
end
|
||||
|
||||
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y = xy
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# # create the underlying object (each backend will do this differently)
|
||||
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
|
||||
# isbefore && return false
|
||||
# i = 0
|
||||
# rows = Any[]
|
||||
# row = Any[]
|
||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
||||
# push!(row, subplt.plts[i].o)
|
||||
# if c == ncols(subplt.layout, r)
|
||||
# push!(rows, Qwt.hsplitter(row...))
|
||||
# row = Any[]
|
||||
# end
|
||||
# end
|
||||
# # for rowcnt in subplt.layout.rowcounts
|
||||
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
|
||||
# # i += rowcnt
|
||||
# # end
|
||||
# subplt.o = Qwt.vsplitter(rows...)
|
||||
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
|
||||
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
|
||||
# true
|
||||
# end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
|
||||
for series in plt.o.lines
|
||||
_expand_limits(lims, isx ? series.x : series.y)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
|
||||
write(io, readall("/tmp/dfskjdhfkh.png"))
|
||||
end
|
||||
|
||||
# function Base.show(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
|
||||
# for plt in subplt.plts
|
||||
# Qwt.refresh(plt.o)
|
||||
# end
|
||||
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
|
||||
# write(io, readall("/tmp/dfskjdhfkh.png"))
|
||||
# end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.showwidget(plt.o)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
|
||||
# for plt in subplt.plts
|
||||
# Qwt.refresh(plt.o)
|
||||
# end
|
||||
# Qwt.showwidget(subplt.o)
|
||||
# end
|
||||
@@ -1,272 +0,0 @@
|
||||
|
||||
# https://github.com/nolta/Winston.jl
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
supported_attrs(::WinstonBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:linecolor,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:label,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:bins,
|
||||
:title,
|
||||
:window_title,
|
||||
:guide, :lims, :scale,
|
||||
])
|
||||
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
|
||||
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::WinstonBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::WinstonBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _initialize_backend(::WinstonBackend; kw...)
|
||||
@eval begin
|
||||
# ENV["WINSTON_OUTPUT"] = "gtk"
|
||||
@warn("Winston is no longer supported... many features will likely be broken.")
|
||||
import Winston, Gtk
|
||||
export Winston, Gtk
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
## dictionaries for conversion of Plots.jl names to Winston ones.
|
||||
const winston_linestyle = KW(:solid=>"solid",
|
||||
:dash=>"dash",
|
||||
:dot=>"dotted",
|
||||
:dashdot=>"dotdashed"
|
||||
)
|
||||
|
||||
const winston_marker = KW(:none=>".",
|
||||
:rect => "square",
|
||||
:circle=>"circle",
|
||||
:diamond=>"diamond",
|
||||
:utriangle=>"triangle",
|
||||
:dtriangle=>"down-triangle",
|
||||
:cross => "plus",
|
||||
:xcross => "cross",
|
||||
:star5 => "asterisk"
|
||||
)
|
||||
|
||||
function _before_update(plt::Plot{WinstonBackend})
|
||||
Winston.ghf(plt.o)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_backend_figure(plt::Plot{WinstonBackend})
|
||||
Winston.FramedPlot(
|
||||
title = plt.attr[:title],
|
||||
xlabel = plt.attr[:xguide],
|
||||
ylabel = plt.attr[:yguide]
|
||||
)
|
||||
end
|
||||
|
||||
copy_remove(plotattributes::KW, s::Symbol) = delete!(copy(plotattributes), s)
|
||||
|
||||
function addRegressionLineWinston(plotattributes::KW, wplt)
|
||||
xs, ys = regressionXY(plotattributes[:x], plotattributes[:y])
|
||||
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
|
||||
end
|
||||
|
||||
function getWinstonItems(plt::Plot)
|
||||
if isa(plt.o, Winston.FramedPlot)
|
||||
wplt = plt.o
|
||||
window, canvas = nothing, nothing
|
||||
else
|
||||
window, canvas, wplt = plt.o
|
||||
end
|
||||
window, canvas, wplt
|
||||
end
|
||||
|
||||
function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
||||
plotattributes = series.plotattributes
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
# until we call it normally, do the hack
|
||||
if plotattributes[:seriestype] == :bar
|
||||
plotattributes = barHack(;plotattributes...)
|
||||
end
|
||||
|
||||
|
||||
e = KW()
|
||||
e[:color] = getColor(plotattributes[:linecolor])
|
||||
e[:linewidth] = plotattributes[:linewidth]
|
||||
e[:kind] = winston_linestyle[plotattributes[:linestyle]]
|
||||
e[:symbolkind] = winston_marker[plotattributes[:markershape]]
|
||||
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
|
||||
e[:symbolsize] = plotattributes[:markersize] / 5
|
||||
|
||||
# pos # (Int,Int), move the enclosing window to this position
|
||||
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
||||
|
||||
|
||||
|
||||
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
|
||||
if plotattributes[:seriestype] == :none
|
||||
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
|
||||
|
||||
elseif plotattributes[:seriestype] == :path
|
||||
x, y = plotattributes[:x], plotattributes[:y]
|
||||
Winston.add(wplt, Winston.Curve(x, y; e...))
|
||||
|
||||
fillrange = plotattributes[:fillrange]
|
||||
if fillrange != nothing
|
||||
if isa(fillrange, AbstractVector)
|
||||
y2 = fillrange
|
||||
else
|
||||
y2 = Float64[fillrange for yi in y]
|
||||
end
|
||||
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(plotattributes[:fillcolor])))
|
||||
end
|
||||
|
||||
elseif plotattributes[:seriestype] == :scatter
|
||||
if plotattributes[:markershape] == :none
|
||||
plotattributes[:markershape] = :circle
|
||||
end
|
||||
|
||||
# elseif plotattributes[:seriestype] == :step
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif plotattributes[:seriestype] == :stepinverted
|
||||
# fn = Winston.XXX
|
||||
|
||||
elseif plotattributes[:seriestype] == :sticks
|
||||
Winston.add(wplt, Winston.Stems(plotattributes[:x], plotattributes[:y]; e...))
|
||||
|
||||
# elseif plotattributes[:seriestype] == :dots
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif plotattributes[:seriestype] == :histogram2d
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif plotattributes[:seriestype] == :hexbin
|
||||
# fn = Winston.XXX
|
||||
|
||||
elseif plotattributes[:seriestype] == :histogram
|
||||
hst = hist(plotattributes[:y], plotattributes[:bins])
|
||||
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
|
||||
|
||||
# elseif plotattributes[:seriestype] == :bar
|
||||
# # fn = Winston.XXX
|
||||
|
||||
else
|
||||
error("seriestype $(plotattributes[:seriestype]) not supported by Winston.")
|
||||
|
||||
end
|
||||
|
||||
|
||||
# markershape
|
||||
if plotattributes[:markershape] != :none
|
||||
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
|
||||
end
|
||||
|
||||
|
||||
# optionally add a regression line
|
||||
plotattributes[:smooth] && plotattributes[:seriestype] != :histogram && addRegressionLineWinston(plotattributes, wplt)
|
||||
|
||||
# push!(plt.seriesargs, plotattributes)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _winstonNames = KW(
|
||||
:xlims => :xrange,
|
||||
:ylims => :yrange,
|
||||
:xscale => :xlog,
|
||||
:yscale => :ylog,
|
||||
)
|
||||
|
||||
function _update_plot_object(plt::Plot{WinstonBackend}, plotattributes::KW)
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
for k in (:xguide, :yguide, :title, :xlims, :ylims)
|
||||
if haskey(plotattributes, k)
|
||||
Winston.setattr(wplt, string(get(_winstonNames, k, k)), plotattributes[k])
|
||||
end
|
||||
end
|
||||
|
||||
for k in (:xscale, :yscale)
|
||||
if haskey(plotattributes, k)
|
||||
islogscale = plotattributes[k] == :log10
|
||||
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::AbstractString)
|
||||
Winston.text(x, y, val)
|
||||
end
|
||||
|
||||
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
||||
for ann in anns
|
||||
createWinstonAnnotationObject(plt, ann...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
|
||||
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function addWinstonLegend(plt::Plot, wplt)
|
||||
if plt.attr[:legend] != :none
|
||||
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
|
||||
end
|
||||
end
|
||||
|
||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
addWinstonLegend(plt, wplt)
|
||||
show(io, "image/png", wplt)
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
|
||||
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
if window == nothing
|
||||
if Winston.output_surface != :gtk
|
||||
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
|
||||
end
|
||||
# initialize window
|
||||
w,h = plt.attr[:size]
|
||||
canvas = Gtk.GtkCanvasLeaf()
|
||||
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
|
||||
plt.o = (window, canvas, wplt)
|
||||
end
|
||||
|
||||
addWinstonLegend(plt, wplt)
|
||||
|
||||
Winston.display(canvas, wplt)
|
||||
Gtk.showall(window)
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
|
||||
# # TODO: display/show the Subplot object
|
||||
# end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,415 +0,0 @@
|
||||
|
||||
abstract type ColorScheme end
|
||||
|
||||
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
|
||||
|
||||
export
|
||||
cgrad
|
||||
|
||||
cgrad() = default_gradient()
|
||||
|
||||
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
|
||||
colors = ColorGradient(arg, alpha=alpha).colors
|
||||
values = if values != nothing
|
||||
values
|
||||
elseif scale in (:log, :log10)
|
||||
log10(range(1, stop=10, length=30))
|
||||
elseif scale == :log2
|
||||
log2(range(1, stop=2, length=30))
|
||||
elseif scale == :ln
|
||||
log(range(1, stop=pi, length=30))
|
||||
elseif scale in (:exp, :exp10)
|
||||
(exp10(range(0, stop=1, length=30)) - 1) / 9
|
||||
else
|
||||
range(0, stop=1, length=length(colors))
|
||||
end
|
||||
ColorGradient(colors, values)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
getColor(scheme::ColorScheme) = getColor(scheme, 1)
|
||||
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
|
||||
|
||||
colorscheme(scheme::ColorScheme) = scheme
|
||||
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
|
||||
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
|
||||
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
|
||||
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
|
||||
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
|
||||
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
|
||||
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
|
||||
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
|
||||
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
|
||||
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
|
||||
convertColor(c::AbstractString) = parse(Colorant, c)
|
||||
convertColor(c::Symbol) = parse(Colorant, string(c))
|
||||
convertColor(c::Colorant) = c
|
||||
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
|
||||
convertColor(c::ColorScheme) = c
|
||||
convertColor(v::Nothing) = RGBA(0,0,0,0)
|
||||
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
|
||||
|
||||
function convertColor(c, α::Real)
|
||||
c = convertColor(c)
|
||||
RGBA(RGB(getColor(c)), α)
|
||||
end
|
||||
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
|
||||
convertColor(c, α::Nothing) = convertColor(c)
|
||||
|
||||
# backup... try to convert
|
||||
getColor(c) = convertColor(c)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
function darken(c, v=0.1)
|
||||
rgba = convert(RGBA, c)
|
||||
r = max(0, min(rgba.r - v, 1))
|
||||
g = max(0, min(rgba.g - v, 1))
|
||||
b = max(0, min(rgba.b - v, 1))
|
||||
RGBA(r,g,b,rgba.alpha)
|
||||
end
|
||||
function lighten(c, v=0.3)
|
||||
darken(c, -v)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
|
||||
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
|
||||
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
|
||||
|
||||
const _gradients = KW(
|
||||
:blues => [colorant"lightblue", colorant"darkblue"],
|
||||
:reds => [colorant"lightpink", colorant"darkred"],
|
||||
:greens => [colorant"lightgreen", colorant"darkgreen"],
|
||||
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
|
||||
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
|
||||
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
|
||||
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
|
||||
:rainbow => _rainbowColors,
|
||||
:lightrainbow => map(lighten, _rainbowColors),
|
||||
:darkrainbow => map(darken, _rainbowColors),
|
||||
:darktest => _testColors,
|
||||
:lighttest => map(c -> lighten(c, 0.3), _testColors),
|
||||
)
|
||||
|
||||
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
|
||||
_gradients[name] = colors
|
||||
end
|
||||
|
||||
include("color_gradients.jl")
|
||||
|
||||
default_gradient() = ColorGradient(:inferno)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
|
||||
struct ColorGradient <: ColorScheme
|
||||
colors::Vector
|
||||
values::Vector
|
||||
|
||||
function ColorGradient(cs::AVec, vals::AVec{S} = range(0, stop=1, length=length(cs)); alpha = nothing) where S<:Real
|
||||
if length(cs) == length(vals)
|
||||
return new(convertColor(cs,alpha), collect(vals))
|
||||
end
|
||||
|
||||
# # otherwise interpolate evenly between the minval and maxval
|
||||
# minval, maxval = minimum(vals), maximum(vals)
|
||||
# vs = Float64[interpolate(minval, maxval, w) for w in range(0, stop = 1, length = length(cs))]
|
||||
# new(convertColor(cs,alpha), vs)
|
||||
|
||||
# interpolate the colors for each value
|
||||
vals = merge(range(0, stop=1, length=length(cs)), vals)
|
||||
grad = ColorGradient(cs)
|
||||
cs = [getColorZ(grad, z) for z in range(0, stop=1, length=length(vals))]
|
||||
new(convertColor(cs, alpha), vals)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
|
||||
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
|
||||
|
||||
|
||||
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
|
||||
function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
|
||||
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
|
||||
cs = _gradients[s]
|
||||
if vals == 0:0
|
||||
vals = range(0, stop=1, length=length(cs))
|
||||
end
|
||||
ColorGradient(cs, vals; kw...)
|
||||
end
|
||||
|
||||
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
|
||||
# ColorGradient(map(convertColor, cs), vals; kw...)
|
||||
# end
|
||||
|
||||
function ColorGradient(grad::ColorGradient; alpha = nothing)
|
||||
ColorGradient(convertColor(grad.colors, alpha), grad.values)
|
||||
end
|
||||
|
||||
# anything else just gets the default gradient
|
||||
function ColorGradient(cw; alpha=nothing)
|
||||
ColorGradient(default_gradient(), alpha=alpha)
|
||||
end
|
||||
|
||||
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
|
||||
|
||||
function getColorZ(gradient::ColorGradient, z::Real)
|
||||
cs = gradient.colors
|
||||
vs = gradient.values
|
||||
n = length(cs)
|
||||
@assert n > 0 && n == length(vs)
|
||||
|
||||
# can we just return the first color?
|
||||
if z <= vs[1] || n == 1
|
||||
return cs[1]
|
||||
end
|
||||
|
||||
# find the bounding colors and interpolate
|
||||
for i in 2:n
|
||||
if z <= vs[i]
|
||||
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
|
||||
end
|
||||
end
|
||||
|
||||
# if we get here, return the last color
|
||||
cs[end]
|
||||
end
|
||||
|
||||
getColorVector(gradient::ColorGradient) = gradient.colors
|
||||
|
||||
# for 0.3
|
||||
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
|
||||
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
|
||||
|
||||
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
|
||||
rgb1 = RGBA(c1)
|
||||
rgb2 = RGBA(c2)
|
||||
r = interpolate(rgb1.r, rgb2.r, w)
|
||||
g = interpolate(rgb1.g, rgb2.g, w)
|
||||
b = interpolate(rgb1.b, rgb2.b, w)
|
||||
a = interpolate(rgb1.alpha, rgb2.alpha, w)
|
||||
RGBA(r, g, b, a)
|
||||
end
|
||||
|
||||
|
||||
function interpolate(v1::Real, v2::Real, w::Real)
|
||||
(1-w) * v1 + w * v2
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a function, taking an index and returning a Colorant"
|
||||
struct ColorFunction <: ColorScheme
|
||||
f::Function
|
||||
end
|
||||
|
||||
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a function, taking an z-value and returning a Colorant"
|
||||
struct ColorZFunction <: ColorScheme
|
||||
f::Function
|
||||
end
|
||||
|
||||
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
|
||||
struct ColorVector <: ColorScheme
|
||||
v::Vector{Colorant}
|
||||
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
|
||||
end
|
||||
|
||||
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
|
||||
getColorVector(scheme::ColorVector) = scheme.v
|
||||
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
"Wraps a single color"
|
||||
struct ColorWrapper <: ColorScheme
|
||||
c::RGBA
|
||||
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
|
||||
end
|
||||
|
||||
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
|
||||
|
||||
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
|
||||
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
|
||||
convertColor(c::ColorWrapper, α::Nothing) = c.c
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
|
||||
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
|
||||
|
||||
# move closer to lighter/darker depending on background value
|
||||
function adjustAway(val, bgval, vmin=0., vmax=100.)
|
||||
if bgval < 0.5 * (vmax+vmin)
|
||||
tmp = max(val, bgval)
|
||||
return 0.5 * (tmp + max(tmp, vmax))
|
||||
else
|
||||
tmp = min(val, bgval)
|
||||
return 0.5 * (tmp + min(tmp, vmin))
|
||||
end
|
||||
end
|
||||
|
||||
# borrowed from http://stackoverflow.com/a/1855903:
|
||||
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
|
||||
|
||||
isdark(c::Colorant) = lightnessLevel(c) < 0.5
|
||||
islight(c::Colorant) = !isdark(c)
|
||||
|
||||
function convertHexToRGB(h::Unsigned)
|
||||
mask = 0x0000FF
|
||||
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
|
||||
end
|
||||
|
||||
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
|
||||
const _masterColorList = [
|
||||
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
|
||||
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
|
||||
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
|
||||
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
|
||||
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
|
||||
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
|
||||
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
|
||||
]
|
||||
const _allColors = map(convertHexToRGB, _masterColorList)
|
||||
const _darkColors = filter(isdark, _allColors)
|
||||
const _lightColors = filter(islight, _allColors)
|
||||
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
|
||||
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
|
||||
|
||||
const _defaultNumColors = 17
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
# Methods to automatically generate gradients for color selection based on
|
||||
# background color and a short list of seed colors
|
||||
|
||||
# here are some magic constants that could be changed if you really want
|
||||
const _lightness_darkbg = [80.0]
|
||||
const _lightness_lightbg = [60.0]
|
||||
const _lch_c_const = [60]
|
||||
|
||||
function adjust_lch(color, l, c)
|
||||
lch = convert(LCHab, color)
|
||||
convert(RGB, LCHab(l, c, lch.h))
|
||||
end
|
||||
|
||||
function lightness_from_background(bgcolor)
|
||||
bglight = convert(LCHab, bgcolor).l
|
||||
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
|
||||
end
|
||||
|
||||
function gradient_from_list(cs)
|
||||
zvalues = Plots.get_zvalues(length(cs))
|
||||
indices = sortperm(zvalues)
|
||||
sorted_colors = map(RGBA, cs[indices])
|
||||
sorted_zvalues = zvalues[indices]
|
||||
ColorGradient(sorted_colors, sorted_zvalues)
|
||||
end
|
||||
|
||||
function generate_colorgradient(bgcolor = colorant"white";
|
||||
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
|
||||
lightness = lightness_from_background(bgcolor),
|
||||
chroma = _lch_c_const[1],
|
||||
n = _defaultNumColors)
|
||||
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
|
||||
colors = distinguishable_colors(n,
|
||||
seed_colors,
|
||||
lchoices=Float64[lightness],
|
||||
cchoices=Float64[chroma],
|
||||
hchoices=range(0, stop=340, length=20)
|
||||
)[2:end]
|
||||
gradient_from_list(colors)
|
||||
end
|
||||
|
||||
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
|
||||
grad = if palette == :auto
|
||||
generate_colorgradient(bgcolor)
|
||||
else
|
||||
ColorGradient(palette)
|
||||
end
|
||||
zrng = get_zvalues(numcolors)
|
||||
RGBA[getColorZ(grad, z) for z in zrng]
|
||||
end
|
||||
|
||||
function get_color_palette(palette::Vector{C},
|
||||
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
|
||||
palette
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function getpctrange(n::Int)
|
||||
n > 0 || error()
|
||||
n == 1 && return zeros(1)
|
||||
zs = [0.0, 1.0]
|
||||
for i in 3:n
|
||||
sorted = sort(zs)
|
||||
diffs = diff(sorted)
|
||||
widestj = 0
|
||||
widest = 0.0
|
||||
for (j,d) in enumerate(diffs)
|
||||
if d > widest
|
||||
widest = d
|
||||
widestj = j
|
||||
end
|
||||
end
|
||||
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
|
||||
end
|
||||
zs
|
||||
end
|
||||
|
||||
function get_zvalues(n::Int)
|
||||
offsets = getpctrange(ceil(Int,n/4)+1)/4
|
||||
offsets = vcat(offsets[1], offsets[3:end])
|
||||
zvalues = Float64[]
|
||||
for offset in offsets
|
||||
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
|
||||
end
|
||||
vcat(zvalues[1], 1.0, zvalues[2:n-1])
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
make255(x) = round(Int, 255 * x)
|
||||
|
||||
function webcolor(c::Color)
|
||||
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
|
||||
end
|
||||
function webcolor(c::TransparentColor)
|
||||
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
|
||||
end
|
||||
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
|
||||
webcolor(c) = webcolor(convertColor(c))
|
||||
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
|
||||
function getSeriesRGBColor(c, sp::Subplot, n::Int)
|
||||
|
||||
if c == :auto
|
||||
c = autopick(sp[:color_palette], n)
|
||||
end
|
||||
|
||||
# c should now be a subtype of ColorScheme
|
||||
colorscheme(c)
|
||||
end
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
|
||||
# TODO:
|
||||
"""
|
||||
- load Contours.jl similar to DataFrames
|
||||
- method to build grid from x/y/z vectors
|
||||
- method to wrap contours creation
|
||||
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
# # ----------------------------------------------------------
|
||||
# # ----------------------------------------------------------
|
||||
|
||||
|
||||
# immutable Vertex
|
||||
# x::Float64
|
||||
# y::Float64
|
||||
# z::Float64
|
||||
# end
|
||||
|
||||
# immutable Edge
|
||||
# v::Vertex
|
||||
# u::Vertex
|
||||
# end
|
||||
|
||||
# # ----------------------------------------------------------
|
||||
|
||||
# # one rectangle's z-values and the center vertex
|
||||
# # z is ordered: topleft, topright, bottomright, bottomleft
|
||||
# immutable GridRect
|
||||
# z::Vector{Float64}
|
||||
# center::Vertex
|
||||
# data::Vector{Vertex}
|
||||
# end
|
||||
|
||||
|
||||
|
||||
# type Grid
|
||||
# xs::Vector{Float64}
|
||||
# ys::Vector{Float64}
|
||||
# rects::Matrix{GridRect}
|
||||
# end
|
||||
|
||||
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
|
||||
# vs = sort(v)
|
||||
|
||||
# end
|
||||
|
||||
# # the goal here is to create the vertical and horizontal partitions
|
||||
# # which define the grid, so that the data is somewhat evenly split
|
||||
# function bucketData(x, y, z)
|
||||
|
||||
# end
|
||||
|
||||
|
||||
# function buildGrid(x, y, z)
|
||||
# # create
|
||||
# end
|
||||
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
|
||||
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
|
||||
# Special handling for: no args, xmin/xmax, parametric, dataframes
|
||||
# Then once inputs have been converted, build the series args, map functions, etc.
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
const FuncOrFuncs = Union{Function, AVec{Function}}
|
||||
|
||||
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(plotattributes, :seriestype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
|
||||
|
||||
function convertToAnyVector(v::AMat, plotattributes::KW)
|
||||
if all3D(plotattributes)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
|
||||
|
||||
# # vector of OHLC
|
||||
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, plotattributes::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
|
||||
|
||||
|
||||
function convertToAnyVector(args...)
|
||||
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
|
||||
# result in that array being shared. push!, etc will add too many items to that array
|
||||
|
||||
compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1)
|
||||
compute_x(x::Nothing, y, z) = 1:size(y,1)
|
||||
compute_x(x::Function, y, z) = map(x, y)
|
||||
compute_x(x, y, z) = copy(x)
|
||||
|
||||
# compute_y(x::Void, y::Function, z) = error()
|
||||
compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2)
|
||||
compute_y(x, y::Function, z) = map(y, x)
|
||||
compute_y(x, y, z) = copy(y)
|
||||
|
||||
compute_z(x, y, z::Function) = map(z, x, y)
|
||||
compute_z(x, y, z::AbstractMatrix) = Surface(z)
|
||||
compute_z(x, y, z::Nothing) = nothing
|
||||
compute_z(x, y, z) = copy(z)
|
||||
|
||||
nobigs(v::AVec{BigFloat}) = map(Float64, v)
|
||||
nobigs(v::AVec{BigInt}) = map(Int64, v)
|
||||
nobigs(v) = v
|
||||
|
||||
@noinline function compute_xyz(x, y, z)
|
||||
x = compute_x(x,y,z)
|
||||
y = compute_y(x,y,z)
|
||||
z = compute_z(x,y,z)
|
||||
nobigs(x), nobigs(y), nobigs(z)
|
||||
end
|
||||
|
||||
# not allowed
|
||||
compute_xyz(x::Nothing, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
|
||||
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
+30
-1
@@ -435,8 +435,37 @@ each line segment or marker in the plot.
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Portfolio Composition maps",
|
||||
"""
|
||||
see: http://stackoverflow.com/a/37732384/5075246
|
||||
""",
|
||||
[:(begin
|
||||
using Random
|
||||
Random.seed!(111)
|
||||
tickers = ["IBM", "Google", "Apple", "Intel"]
|
||||
N = 10
|
||||
D = length(tickers)
|
||||
weights = rand(N,D)
|
||||
weights ./= sum(weights, dims = 2)
|
||||
returns = sort!((1:N) + D*randn(N))
|
||||
|
||||
portfoliocomposition(weights, returns, labels = permutedims(tickers))
|
||||
end)]
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
# Some constants for PlotDocs and PlotReferenceImages
|
||||
_animation_examples = [2, 30]
|
||||
_backend_skips = Dict(
|
||||
:gr => [25, 30],
|
||||
:pyplot => [25, 30],
|
||||
:plotlyjs => [2, 21, 25, 30, 31],
|
||||
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30],
|
||||
)
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# make and display one plot
|
||||
@@ -473,7 +502,7 @@ function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = noth
|
||||
plts[i] = plt
|
||||
catch ex
|
||||
# TODO: put error info into markdown?
|
||||
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
|
||||
@warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
|
||||
end
|
||||
if sleep != nothing
|
||||
Base.sleep(sleep)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# ---------------------------------------------------------
|
||||
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
|
||||
|
||||
_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString)
|
||||
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x)
|
||||
|
||||
function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
|
||||
fn = tempname()
|
||||
|
||||
# first save a pdf file
|
||||
pdf(plt, fn)
|
||||
|
||||
# load that pdf into a FileIO Stream
|
||||
s = _fileio_load(fn * ".pdf")
|
||||
|
||||
# save a png
|
||||
pngfn = fn * ".png"
|
||||
_fileio_save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, read(open(pngfn), String))
|
||||
end
|
||||
|
||||
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
|
||||
@@ -0,0 +1,59 @@
|
||||
const use_local_dependencies = Ref(false)
|
||||
const use_local_plotlyjs = Ref(false)
|
||||
|
||||
|
||||
function _init_ijulia_plotting()
|
||||
# IJulia is more stable with local file
|
||||
use_local_plotlyjs[] = isfile(plotly_local_file_path)
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Add extra jupyter mimetypes to display_dict based on the plot backed.
|
||||
|
||||
The default is nothing, except for plotly based backends, where it
|
||||
adds data for `application/vnd.plotly.v1+json` that is used in
|
||||
frontends like jupyterlab and nteract.
|
||||
"""
|
||||
_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out
|
||||
|
||||
function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
|
||||
out
|
||||
end
|
||||
|
||||
function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
|
||||
function _ijulia_display_dict(plt::Plot)
|
||||
output_type = Symbol(plt.attr[:html_output_format])
|
||||
if output_type == :auto
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
out = Dict()
|
||||
if output_type == :txt
|
||||
mime = "text/plain"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :png
|
||||
mime = "image/png"
|
||||
out[mime] = base64encode(show, MIME(mime), plt)
|
||||
elseif output_type == :svg
|
||||
mime = "image/svg+xml"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :html
|
||||
mime = "text/html"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
else
|
||||
error("Unsupported output type $output_type")
|
||||
end
|
||||
_ijulia__extra_mime_info!(plt, out)
|
||||
out
|
||||
end
|
||||
+39
-66
@@ -1,26 +1,33 @@
|
||||
function __init__()
|
||||
using REPL
|
||||
|
||||
|
||||
function _plots_defaults()
|
||||
if isdefined(Main, :PLOTS_DEFAULTS)
|
||||
if haskey(Main.PLOTS_DEFAULTS, :theme)
|
||||
theme(Main.PLOTS_DEFAULTS[:theme])
|
||||
end
|
||||
for (k,v) in Main.PLOTS_DEFAULTS
|
||||
k == :theme || default(k, v)
|
||||
end
|
||||
Main.PLOTS_DEFAULTS::Dict{Symbol,Any}
|
||||
else
|
||||
Dict{Symbol,Any}()
|
||||
end
|
||||
pushdisplay(PlotsDisplay())
|
||||
end
|
||||
|
||||
|
||||
function __init__()
|
||||
user_defaults = _plots_defaults()
|
||||
if haskey(user_defaults, :theme)
|
||||
theme(user_defaults[:theme])
|
||||
end
|
||||
for (k,v) in user_defaults
|
||||
k == :theme || default(k, v)
|
||||
end
|
||||
|
||||
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
|
||||
|
||||
atreplinit(i -> begin
|
||||
if PlotDisplay() in Base.Multimedia.displays
|
||||
while PlotsDisplay() in Base.Multimedia.displays
|
||||
popdisplay(PlotsDisplay())
|
||||
end
|
||||
pushdisplay(PlotsDisplay())
|
||||
insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
|
||||
end)
|
||||
|
||||
include(joinpath(@__DIR__, "backends", "plotly.jl"))
|
||||
include(joinpath(@__DIR__, "backends", "gr.jl"))
|
||||
include(joinpath(@__DIR__, "backends", "web.jl"))
|
||||
|
||||
@require GLVisualize = "4086de5b-f4b6-55f3-abb0-b8c73827585f" include(joinpath(@__DIR__, "backends", "glvisualize.jl"))
|
||||
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
|
||||
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
|
||||
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
|
||||
@@ -28,60 +35,26 @@ function __init__()
|
||||
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl"))
|
||||
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl"))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# IJulia
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
|
||||
if IJulia.inited
|
||||
_init_ijulia_plotting()
|
||||
|
||||
"""
|
||||
Add extra jupyter mimetypes to display_dict based on the plot backed.
|
||||
|
||||
The default is nothing, except for plotly based backends, where it
|
||||
adds data for `application/vnd.plotly.v1+json` that is used in
|
||||
frontends like jupyterlab and nteract.
|
||||
"""
|
||||
_extra_mime_info!(plt::Plot, out::Dict) = out
|
||||
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
|
||||
out
|
||||
end
|
||||
|
||||
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
|
||||
out["application/vnd.plotly.v1+json"] = Dict(
|
||||
:data => plotly_series(plt),
|
||||
:layout => plotly_layout(plt)
|
||||
)
|
||||
out
|
||||
end
|
||||
|
||||
function IJulia.display_dict(plt::Plot)
|
||||
output_type = Symbol(plt.attr[:html_output_format])
|
||||
if output_type == :auto
|
||||
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
|
||||
end
|
||||
out = Dict()
|
||||
if output_type == :txt
|
||||
mime = "text/plain"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :png
|
||||
mime = "image/png"
|
||||
out[mime] = base64encode(show, MIME(mime), plt)
|
||||
elseif output_type == :svg
|
||||
mime = "image/svg+xml"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
elseif output_type == :html
|
||||
mime = "text/html"
|
||||
out[mime] = sprint(show, MIME(mime), plt)
|
||||
else
|
||||
error("Unsupported output type $output_type")
|
||||
end
|
||||
_extra_mime_info!(plt, out)
|
||||
out
|
||||
end
|
||||
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
IJulia.display_dict(plt::Plot) = _ijulia_display_dict(plt)
|
||||
end
|
||||
end
|
||||
|
||||
if haskey(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL")
|
||||
use_local_plotlyjs[] = ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] == "true"
|
||||
use_local_dependencies[] = isfile(plotly_local_file_path) && use_local_plotlyjs[]
|
||||
if use_local_plotlyjs[] && !isfile(plotly_local_file_path)
|
||||
@warn("PLOTS_HOST_DEPENDENCY_LOCAL is set to true, but no local plotly file found. run Pkg.build(\"Plots\") and make sure PLOTS_HOST_DEPENDENCY_LOCAL is set to true")
|
||||
end
|
||||
else
|
||||
use_local_dependencies[] = use_local_plotlyjs[]
|
||||
end
|
||||
|
||||
|
||||
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
|
||||
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -156,7 +156,6 @@ end
|
||||
const _best_html_output_type = KW(
|
||||
:pyplot => :png,
|
||||
:unicodeplots => :txt,
|
||||
:glvisualize => :png,
|
||||
:plotlyjs => :html,
|
||||
:plotly => :html
|
||||
)
|
||||
@@ -210,30 +209,6 @@ _show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
|
||||
closeall() = closeall(backend())
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
|
||||
|
||||
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
|
||||
if is_installed("FileIO")
|
||||
@eval import FileIO
|
||||
function _show(io::IO, ::MIME"image/png", plt::Plot{<:PDFBackends})
|
||||
fn = tempname()
|
||||
|
||||
# first save a pdf file
|
||||
pdf(plt, fn)
|
||||
|
||||
# load that pdf into a FileIO Stream
|
||||
s = FileIO.load(fn * ".pdf")
|
||||
|
||||
# save a png
|
||||
pngfn = fn * ".png"
|
||||
FileIO.save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, read(open(pngfn), String))
|
||||
end
|
||||
end
|
||||
|
||||
# function html_output_format(fmt)
|
||||
# if fmt == "png"
|
||||
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
|
||||
|
||||
+2
-2
@@ -166,9 +166,9 @@ end
|
||||
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
|
||||
plotattributes[:plot_object] = plt
|
||||
|
||||
if !isempty(args) && !isdefined(Main, :StatPlots) &&
|
||||
if !isempty(args) && !isdefined(Main, :StatsPlots) &&
|
||||
first(split(string(typeof(args[1])), ".")) == "DataFrames"
|
||||
@warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
|
||||
@warn("You're trying to plot a DataFrame, but this functionality is provided by StatsPlots")
|
||||
end
|
||||
|
||||
# --------------------------------
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ end
|
||||
plotattr([attr])
|
||||
|
||||
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
|
||||
The information is the same as that given on https://juliaplots.github.io/attributes/.
|
||||
The information is the same as that given on https://docs.juliaplots.org/latest/attributes/.
|
||||
"""
|
||||
function plotattr()
|
||||
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
|
||||
|
||||
+36
-6
@@ -586,12 +586,12 @@ end
|
||||
end
|
||||
Plots.@deps stepbins path
|
||||
|
||||
wand_edges(x...) = (@warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
||||
wand_edges(x...) = (@warn("Load the StatsPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
|
||||
|
||||
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
|
||||
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
|
||||
_cl(x) = ceil(Int, max(x, one(x)))
|
||||
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
|
||||
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
|
||||
_span(v) = maximum(v) - minimum(v)
|
||||
|
||||
n_samples = length(LinearIndices(first(vs)))
|
||||
|
||||
@@ -635,11 +635,19 @@ _hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, Abstra
|
||||
_hist_norm_mode(mode::Symbol) = mode
|
||||
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
|
||||
|
||||
_filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs)
|
||||
function _filternans(vs::NTuple{N,AbstractVector}) where N
|
||||
_invertedindex(v, not) = [j for (i,j) in enumerate(v) if !(i ∈ not)]
|
||||
nots = union(Set.(findall.(!isfinite, vs))...)
|
||||
_invertedindex.(vs, Ref(nots))
|
||||
end
|
||||
|
||||
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
|
||||
edges = _hist_edges(vs, binning)
|
||||
localvs = _filternans(vs)
|
||||
edges = _hist_edges(localvs, binning)
|
||||
h = float( weights == nothing ?
|
||||
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
|
||||
StatsBase.fit(StatsBase.Histogram, vs, StatsBase.Weights(weights), edges, closed = :left)
|
||||
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
|
||||
StatsBase.fit(StatsBase.Histogram, localvs, StatsBase.Weights(weights), edges, closed = :left)
|
||||
)
|
||||
normalize!(h, mode = _hist_norm_mode(normed))
|
||||
end
|
||||
@@ -1131,3 +1139,25 @@ end
|
||||
title := string(grad.args[1])
|
||||
z
|
||||
end
|
||||
|
||||
|
||||
# Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246
|
||||
@userplot PortfolioComposition
|
||||
|
||||
# this shows the shifting composition of a basket of something over a variable
|
||||
# - "returns" are the dependent variable
|
||||
# - "weights" are a matrix where the ith column is the composition for returns[i]
|
||||
# - since each polygon is its own series, you can assign labels easily
|
||||
@recipe function f(pc::PortfolioComposition)
|
||||
weights, returns = pc.args
|
||||
n = length(returns)
|
||||
weights = cumsum(weights, dims = 2)
|
||||
seriestype := :shape
|
||||
|
||||
# create a filled polygon for each item
|
||||
for c=1:size(weights,2)
|
||||
sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1]))
|
||||
sy = vcat(returns, reverse(returns))
|
||||
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
|
||||
end
|
||||
end
|
||||
|
||||
+28
-13
@@ -323,19 +323,26 @@ end
|
||||
|
||||
|
||||
# # images - grays
|
||||
function clamp_greys!(mat::AMat{T}) where T<:Gray
|
||||
for i in eachindex(mat)
|
||||
mat[i].val < 0 && (mat[i] = Gray(0))
|
||||
mat[i].val > 1 && (mat[i] = Gray(1))
|
||||
end
|
||||
mat
|
||||
end
|
||||
|
||||
@recipe function f(mat::AMat{T}) where T<:Gray
|
||||
n, m = size(mat)
|
||||
if is_seriestype_supported(:image)
|
||||
seriestype := :image
|
||||
yflip --> true
|
||||
SliceIt, 1:m, 1:n, Surface(mat)
|
||||
SliceIt, 1:m, 1:n, Surface(clamp_greys!(mat))
|
||||
else
|
||||
seriestype := :heatmap
|
||||
yflip --> true
|
||||
cbar --> false
|
||||
fillcolor --> ColorGradient([:black, :white])
|
||||
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
|
||||
SliceIt, 1:m, 1:n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -386,8 +393,9 @@ end
|
||||
xmin, xmax = try
|
||||
axis_limits(plt[1][:xaxis])
|
||||
catch
|
||||
xm = tryrange(f, [-5,-1,0,0.01])
|
||||
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
|
||||
xinv = invscalefunc(get(plotattributes, :xscale, :identity))
|
||||
xm = tryrange(f, xinv.([-5,-1,0,0.01]))
|
||||
xm, tryrange(f, filter(x->x>xm, xinv.([5,1,0.99, 0, -0.01])))
|
||||
end
|
||||
|
||||
f, xmin, xmax
|
||||
@@ -517,16 +525,23 @@ end
|
||||
#
|
||||
# # special handling... xmin/xmax with parametric function(s)
|
||||
@recipe function f(f::Function, xmin::Number, xmax::Number)
|
||||
xs = adapted_grid(f, (xmin, xmax))
|
||||
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
|
||||
xs = _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
|
||||
xs, f
|
||||
end
|
||||
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
|
||||
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
|
||||
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
|
||||
xs = Any[_scaled_adapted_grid(f, xscale, yscale, xmin, xmax) for f in fs]
|
||||
xs, fs
|
||||
end
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n)
|
||||
|
||||
function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
|
||||
(xf, xinv), (yf, yinv) = ((scalefunc(s),invscalefunc(s)) for s in (xscale,yscale))
|
||||
xinv.(adapted_grid(yf∘f∘xinv, xf.((xmin, xmax))))
|
||||
end
|
||||
|
||||
#
|
||||
# # special handling... 3D parametric function(s)
|
||||
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
|
||||
@@ -539,7 +554,7 @@ end
|
||||
#
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
# # Lists of tuples and FixedSizeArrays
|
||||
# # Lists of tuples and StaticArrays
|
||||
# # --------------------------------------------------------------------
|
||||
#
|
||||
# # if we get an unhandled tuple, just splat it in
|
||||
@@ -561,14 +576,14 @@ end
|
||||
|
||||
|
||||
#
|
||||
# # 2D FixedSizeArrays
|
||||
@recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
|
||||
@recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
|
||||
# # 2D StaticArrays
|
||||
@recipe f(xy::AVec{StaticArrays.SVector{2,T}}) where {T<:Number} = unzip(xy)
|
||||
@recipe f(xy::StaticArrays.SVector{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
|
||||
|
||||
#
|
||||
# # 3D FixedSizeArrays
|
||||
@recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
|
||||
@recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
# # 3D StaticArrays
|
||||
@recipe f(xyz::AVec{StaticArrays.SVector{3,T}}) where {T<:Number} = unzip(xyz)
|
||||
@recipe f(xyz::StaticArrays.SVector{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
|
||||
|
||||
#
|
||||
# # --------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
"""
|
||||
scatter(x,y)
|
||||
scatter!(x,y)
|
||||
|
||||
Make a scatter plot of y vs x.
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> scatter([1,2,3],[4,5,6],markersize=[3,4,5],markercolor=[:red,:green,:blue])
|
||||
julia> scatter([(1,4),(2,5),(3,6)])
|
||||
```
|
||||
"""
|
||||
@shorthands scatter
|
||||
|
||||
"""
|
||||
bar(x,y)
|
||||
bar!(x,y)
|
||||
|
||||
Make a bar plot of y vs x.
|
||||
|
||||
# Arguments
|
||||
|
||||
- $(_document_argument("bar_position"))
|
||||
- $(_document_argument("bar_width"))
|
||||
- $(_document_argument("bar_edges"))
|
||||
- $(_document_argument("orientation"))
|
||||
|
||||
# Examples
|
||||
```julia-repl
|
||||
julia> bar([1,2,3],[4,5,6],fillcolor=[:red,:green,:blue],fillalpha=[0.2,0.4,0.6])
|
||||
julia> bar([(1,4),(2,5),(3,6)])
|
||||
```
|
||||
"""
|
||||
@shorthands bar
|
||||
|
||||
@shorthands barh
|
||||
|
||||
"""
|
||||
histogram(x)
|
||||
histogram!(x)
|
||||
|
||||
Plot a histogram.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `x`: AbstractVector of values to be binned
|
||||
- $(_document_argument("bins"))
|
||||
- `weights`: Vector of weights for the values in `x`, for weighted bin counts
|
||||
- $(_document_argument("normalize"))
|
||||
- $(_document_argument("bar_position"))
|
||||
- $(_document_argument("bar_width"))
|
||||
- $(_document_argument("bar_edges"))
|
||||
- $(_document_argument("orientation"))
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> histogram([1,2,1,1,4,3,8],bins=0:8)
|
||||
```
|
||||
"""
|
||||
@shorthands histogram
|
||||
|
||||
"""
|
||||
barhist(x)
|
||||
barhist!(x)
|
||||
|
||||
Make a histogram bar plot. See `histogram`.
|
||||
"""
|
||||
@shorthands barhist
|
||||
|
||||
"""
|
||||
stephist(x)
|
||||
stephist(x)
|
||||
|
||||
Make a histogram step plot (bin counts are represented using horizontal lines
|
||||
instead of bars). See `histogram`.
|
||||
"""
|
||||
@shorthands stephist
|
||||
|
||||
"""
|
||||
scatterhist(x)
|
||||
scatterhist!(x)
|
||||
|
||||
Make a histogram scatter plot (bin counts are represented using points
|
||||
instead of bars). See `histogram`.
|
||||
"""
|
||||
@shorthands scatterhist
|
||||
|
||||
"""
|
||||
histogram2d(x,y)
|
||||
histogram2d!(x,y)
|
||||
|
||||
Plot a two-dimensional histogram.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
|
||||
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
|
||||
its weight to the height of its bin.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> histogram2d(randn(10_000),randn(10_000))
|
||||
```
|
||||
"""
|
||||
@shorthands histogram2d
|
||||
|
||||
"""
|
||||
density(x)
|
||||
density!(x)
|
||||
|
||||
Make a line plot of a kernel density estimate of x.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `x`: AbstractVector of samples for probability density estimation
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> using StatsPlots
|
||||
julia> density(randn(100_000))
|
||||
```
|
||||
"""
|
||||
@shorthands density
|
||||
|
||||
"""
|
||||
heatmap(x,y,z)
|
||||
heatmap!(x,y,z)
|
||||
|
||||
Plot a heatmap of the rectangular array `z`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> heatmap(randn(10,10))
|
||||
```
|
||||
"""
|
||||
@shorthands heatmap
|
||||
@shorthands plots_heatmap
|
||||
|
||||
"""
|
||||
hexbin(x,y)
|
||||
hexbin!(x,y)
|
||||
|
||||
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
|
||||
with hexagonal bins)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> hexbin(randn(10_000), randn(10_000))
|
||||
```
|
||||
"""
|
||||
@shorthands hexbin
|
||||
|
||||
"""
|
||||
sticks(x,y)
|
||||
sticks!(x,y)
|
||||
|
||||
Draw a stick plot of y vs x.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> sticks(1:10)
|
||||
```
|
||||
"""
|
||||
@shorthands sticks
|
||||
|
||||
"""
|
||||
hline(y)
|
||||
hline!(y)
|
||||
|
||||
Draw horizontal lines at positions specified by the values in
|
||||
the AbstractVector `y`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> hline([-1,0,2])
|
||||
```
|
||||
"""
|
||||
@shorthands hline
|
||||
|
||||
"""
|
||||
vline(x)
|
||||
vline!(x)
|
||||
|
||||
Draw vertical lines at positions specified by the values in
|
||||
the AbstractVector `x`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> vline([-1,0,2])
|
||||
```
|
||||
"""
|
||||
@shorthands vline
|
||||
|
||||
"""
|
||||
hspan(y)
|
||||
|
||||
Draw a rectangle between the horizontal line at position `y[1]`
|
||||
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
|
||||
then further rectangles are drawn between `y[3]` and `y[4]`,
|
||||
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
|
||||
last entry of `y` is ignored.
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> hspan(1:6)
|
||||
```
|
||||
"""
|
||||
@shorthands hspan
|
||||
|
||||
"""
|
||||
vspan(x)
|
||||
|
||||
Draw a rectangle between the vertical line at position `x[1]`
|
||||
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
|
||||
then further rectangles are drawn between `x[3]` and `x[4]`,
|
||||
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
|
||||
last entry of `x` is ignored.
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> vspan(1:6)
|
||||
```
|
||||
"""
|
||||
@shorthands vspan
|
||||
|
||||
"""
|
||||
ohlc(x,y::Vector{OHLC})
|
||||
ohlc!(x,y::Vector{OHLC})
|
||||
|
||||
Make open-high-low-close plot. Each entry of y is represented by a vertical
|
||||
segment extending from the low value to the high value, with short horizontal
|
||||
segments on the left and right indicating the open and close values, respectively.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> meanprices = cumsum(randn(100))
|
||||
julia> y = OHLC[(p+rand(),p+1,p-1,p+rand()) for p in meanprices]
|
||||
julia> ohlc(y)
|
||||
```
|
||||
"""
|
||||
@shorthands ohlc
|
||||
|
||||
|
||||
"""
|
||||
contour(x,y,z)
|
||||
contour!(x,y,z)
|
||||
|
||||
Draw contour lines of the `Surface` z.
|
||||
|
||||
# Arguments
|
||||
- `levels`: Contour levels (if `AbstractVector`) or number of levels (if `Integer`)
|
||||
- `fill`: Bool. Fill area between contours or draw contours only (false by default)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> x = y = range(-20, 20, length = 100)
|
||||
julia> contour(x, y, (x, y) -> x^2 + y^2)
|
||||
```
|
||||
"""
|
||||
@shorthands contour
|
||||
|
||||
"An alias for `contour` with fill = true."
|
||||
@shorthands contourf
|
||||
|
||||
|
||||
@shorthands contour3d
|
||||
|
||||
"""
|
||||
surface(x,y,z)
|
||||
surface!(x,y,z)
|
||||
|
||||
Draw a 3D surface plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> x = y = range(-3, 3, length = 100)
|
||||
julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
|
||||
```
|
||||
"""
|
||||
@shorthands surface
|
||||
|
||||
"""
|
||||
wireframe(x,y,z)
|
||||
wireframe!(x,y,z)
|
||||
|
||||
Draw a 3D wireframe plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> wireframe(1:10,1:10,randn(10,10))
|
||||
```
|
||||
"""
|
||||
@shorthands wireframe
|
||||
|
||||
"""
|
||||
path3d(x,y,z)
|
||||
path3d!(x,y,z)
|
||||
|
||||
Plot a 3D path from `(x[1],y[1],z[1])` to `(x[2],y[2],z[2])`,
|
||||
..., to `(x[end],y[end],z[end])`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
```
|
||||
"""
|
||||
@shorthands path3d
|
||||
|
||||
"""
|
||||
scatter3d(x,y,z)
|
||||
scatter3d!(x,y,z)
|
||||
|
||||
Make a 3D scatter plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
|
||||
```
|
||||
"""
|
||||
@shorthands scatter3d
|
||||
|
||||
"""
|
||||
boxplot(x, y)
|
||||
boxplot!(x, y)
|
||||
|
||||
Make a box and whisker plot.
|
||||
|
||||
# Keyword arguments
|
||||
- `notch`: Bool. Notch the box plot? (false)
|
||||
- `range`: Real. Values more than range*IQR below the first quartile
|
||||
or above the third quartile are shown as outliers (1.5)
|
||||
- `outliers`: Bool. Show outliers? (true)
|
||||
- `whisker_width`: Real or Symbol. Length of whiskers (:match)
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> using StatsPlots
|
||||
julia> boxplot(repeat([1,2,3],outer=100),randn(300))
|
||||
```
|
||||
"""
|
||||
@shorthands boxplot
|
||||
|
||||
"""
|
||||
violin(x,y,z)
|
||||
violin!(x,y,z)
|
||||
|
||||
Make a violin plot.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> violin(repeat([1,2,3],outer=100),randn(300))
|
||||
```
|
||||
"""
|
||||
@shorthands violin
|
||||
|
||||
"""
|
||||
quiver(x,y,quiver=(u,v))
|
||||
quiver!(x,y,quiver=(u,v))
|
||||
|
||||
Make a quiver (vector field) plot. The `i`th vector extends
|
||||
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
|
||||
```
|
||||
"""
|
||||
@shorthands quiver
|
||||
|
||||
"""
|
||||
curves(x,y)
|
||||
curves!(x,y)
|
||||
|
||||
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
|
||||
with control points `(x[2],y[2]), ..., (x[end-1],y[end]-1)`
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> curves([1,2,3,4],[1,1,2,4])
|
||||
```
|
||||
"""
|
||||
@shorthands curves
|
||||
|
||||
"Plot a pie diagram"
|
||||
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
|
||||
"Plot with seriestype :path3d"
|
||||
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
|
||||
"Add title to an existing plot"
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
|
||||
"Add xlabel to an existing plot"
|
||||
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
|
||||
|
||||
"Add ylabel to an existing plot"
|
||||
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
|
||||
|
||||
"Set xlims for an existing plot"
|
||||
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
|
||||
|
||||
"Set ylims for an existing plot"
|
||||
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
|
||||
|
||||
"Set zlims for an existing plot"
|
||||
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
|
||||
|
||||
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
|
||||
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
|
||||
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
|
||||
|
||||
|
||||
"Set xticks for an existing plot"
|
||||
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
|
||||
|
||||
"Set yticks for an existing plot"
|
||||
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
|
||||
|
||||
xticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
|
||||
yticks!(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
|
||||
|
||||
"""
|
||||
annotate!(anns...)
|
||||
|
||||
Add annotations to an existing plot.
|
||||
|
||||
# Arguments
|
||||
|
||||
- `anns`: An `AbstractVector` of tuples of the form (x,y,text). The text object
|
||||
can be an String or PlotText
|
||||
|
||||
# Example
|
||||
```julia-repl
|
||||
julia> plot(1:10)
|
||||
julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))])
|
||||
```
|
||||
"""
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
|
||||
|
||||
"Flip the current plots' x axis"
|
||||
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
|
||||
|
||||
"Flip the current plots' y axis"
|
||||
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
|
||||
"Specify x axis attributes for an existing plot"
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
|
||||
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
|
||||
+1
-1
@@ -100,7 +100,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
|
||||
end
|
||||
end
|
||||
|
||||
srand(1)
|
||||
Random.seed!(1)
|
||||
|
||||
label := ""
|
||||
colorbar := false
|
||||
|
||||
+43
-16
@@ -287,14 +287,14 @@ unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2]
|
||||
unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
|
||||
unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
|
||||
|
||||
unzip(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
|
||||
unzip(xy::FixedSizeArrays.Vec{2,T}) where {T} = T[xy[1]], T[xy[2]]
|
||||
unzip(xy::AVec{StaticArrays.SVector{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
|
||||
unzip(xy::StaticArrays.SVector{2,T}) where {T} = T[xy[1]], T[xy[2]]
|
||||
|
||||
unzip(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
|
||||
unzip(xyz::FixedSizeArrays.Vec{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
|
||||
unzip(xyz::AVec{StaticArrays.SVector{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
|
||||
unzip(xyz::StaticArrays.SVector{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
|
||||
|
||||
unzip(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
|
||||
unzip(xyuv::FixedSizeArrays.Vec{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
|
||||
unzip(xyuv::AVec{StaticArrays.SVector{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
|
||||
unzip(xyuv::StaticArrays.SVector{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
|
||||
|
||||
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
|
||||
function _expand_limits(lims, x)
|
||||
@@ -357,6 +357,7 @@ const _scale_base = Dict{Symbol, Real}(
|
||||
)
|
||||
|
||||
function _heatmap_edges(v::AVec)
|
||||
length(v) == 1 && return v[1] .+ [-0.5, 0.5]
|
||||
vmin, vmax = ignorenan_extrema(v)
|
||||
extra_min = (v[2] - v[1]) / 2
|
||||
extra_max = (v[end] - v[end - 1]) / 2
|
||||
@@ -412,14 +413,6 @@ end
|
||||
isijulia() = :IJulia in nameof.(collect(values(Base.loaded_modules)))
|
||||
isatom() = :Atom in nameof.(collect(values(Base.loaded_modules)))
|
||||
|
||||
function is_installed(pkgstr::AbstractString)
|
||||
try
|
||||
Pkg.installed(pkgstr) === nothing ? false : true
|
||||
catch
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
istuple(::Tuple) = true
|
||||
istuple(::Any) = false
|
||||
isvector(::AVec) = true
|
||||
@@ -733,7 +726,7 @@ function with(f::Function, args...; kw...)
|
||||
|
||||
# save the backend
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
_pick_default_backend()
|
||||
end
|
||||
oldbackend = CURRENT_BACKEND.sym
|
||||
|
||||
@@ -745,7 +738,7 @@ function with(f::Function, args...; kw...)
|
||||
end
|
||||
|
||||
# # TODO: generalize this strategy to allow args as much as possible
|
||||
# # as in: with(:gadfly, :scatter, :legend, :grid) do; ...; end
|
||||
# # as in: with(:gr, :scatter, :legend, :grid) do; ...; end
|
||||
# # TODO: can we generalize this enough to also do something similar in the plot commands??
|
||||
|
||||
# k = :seriestype
|
||||
@@ -1206,3 +1199,37 @@ end
|
||||
function construct_categorical_data(x::AbstractArray, axis::Axis)
|
||||
map(xi -> axis[:discrete_values][searchsortedfirst(axis[:continuous_values], xi)], x)
|
||||
end
|
||||
|
||||
_fmt_paragraph(paragraph::AbstractString;kwargs...) = _fmt_paragraph(IOBuffer(),paragraph,0;kwargs...)
|
||||
|
||||
function _fmt_paragraph(io::IOBuffer,
|
||||
remaining_text::AbstractString,
|
||||
column_count::Integer;
|
||||
fillwidth=60,
|
||||
leadingspaces=0)
|
||||
|
||||
kwargs = (fillwidth = fillwidth, leadingspaces = leadingspaces)
|
||||
|
||||
m = match(r"(.*?) (.*)",remaining_text)
|
||||
if isa(m,Nothing)
|
||||
if column_count + length(remaining_text) ≤ fillwidth
|
||||
print(io,remaining_text)
|
||||
String(take!(io))
|
||||
else
|
||||
print(io,"\n"*" "^leadingspaces*remaining_text)
|
||||
String(take!(io))
|
||||
end
|
||||
else
|
||||
if column_count + length(m[1]) ≤ fillwidth
|
||||
print(io,"$(m[1]) ")
|
||||
_fmt_paragraph(io,m[2],column_count + length(m[1]) + 1;kwargs...)
|
||||
else
|
||||
print(io,"\n"*" "^leadingspaces*"$(m[1]) ")
|
||||
_fmt_paragraph(io,m[2],leadingspaces;kwargs...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _document_argument(S::AbstractString)
|
||||
_fmt_paragraph("`$S`: "*_arg_desc[Symbol(S)],leadingspaces = 6 + length(S))
|
||||
end
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
StatPlots
|
||||
StatsPlots
|
||||
Images
|
||||
ImageMagick
|
||||
@osx QuartzImageIO
|
||||
|
||||
+16
-1
@@ -4,7 +4,6 @@ using Pkg
|
||||
# ENV["PYTHON"] = ""
|
||||
|
||||
to_add = [
|
||||
PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"),
|
||||
# PackageSpec(url="https://github.com/JuliaStats/KernelDensity.jl.git"),
|
||||
PackageSpec(name="PlotUtils", rev="master"),
|
||||
PackageSpec(name="RecipesBase", rev="master"),
|
||||
@@ -17,12 +16,28 @@ to_add = [
|
||||
]
|
||||
|
||||
if isinteractive()
|
||||
Pkg.develop(PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"))
|
||||
append!(to_add, [
|
||||
PackageSpec(name="FileIO"),
|
||||
PackageSpec(name="ImageMagick"),
|
||||
PackageSpec(name="UnicodePlots"),
|
||||
PackageSpec(name="VisualRegressionTests"),
|
||||
PackageSpec(name="Gtk"),
|
||||
# PlotlyJS:
|
||||
# PackageSpec(name="PlotlyJS"),
|
||||
# PackageSpec(name="Blink"),
|
||||
# PackageSpec(name="ORCA"),
|
||||
# PyPlot:
|
||||
# PackageSpec(name="PyPlot"),
|
||||
# PackageSpec(name="PyCall"),
|
||||
# PackageSpec(name="LaTeXStrings"),
|
||||
])
|
||||
else
|
||||
push!(to_add, PackageSpec(
|
||||
name="PlotReferenceImages",
|
||||
url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git",
|
||||
rev = "sd-tomls"
|
||||
))
|
||||
end
|
||||
|
||||
Pkg.add(to_add)
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ end
|
||||
|
||||
|
||||
using Plots
|
||||
# using StatPlots
|
||||
# using StatsPlots
|
||||
import PlotReferenceImages
|
||||
using Random
|
||||
using Test
|
||||
@@ -29,7 +29,7 @@ default(size=(500,300))
|
||||
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
|
||||
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
|
||||
|
||||
const _current_plots_version = v"0.20.3"
|
||||
import Plots._current_plots_version
|
||||
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2)
|
||||
|
||||
+16
-35
@@ -14,16 +14,19 @@ img_tol = isinteractive() ? 1e-2 : 10e-2
|
||||
@test gr() == Plots.GRBackend()
|
||||
@test backend() == Plots.GRBackend()
|
||||
|
||||
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
|
||||
@static if Sys.islinux()
|
||||
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#@testset "PyPlot" begin
|
||||
# @test pyplot() == Plots.PyPlotBackend()
|
||||
# @test backend() == Plots.PyPlotBackend()
|
||||
# @static if isinteractive()
|
||||
# @testset "PyPlot" begin
|
||||
# @test pyplot() == Plots.PyPlotBackend()
|
||||
# @test backend() == Plots.PyPlotBackend()
|
||||
#
|
||||
# image_comparison_facts(:pyplot, tol=img_tol)
|
||||
#end
|
||||
# image_comparison_facts(:pyplot, tol=img_tol, skip = [2, 25, 30, 31])
|
||||
# end
|
||||
# end
|
||||
|
||||
@testset "UnicodePlots" begin
|
||||
@test unicodeplots() == Plots.UnicodePlotsBackend()
|
||||
@@ -36,22 +39,23 @@ end
|
||||
# The plotlyjs testimages return a connection error on travis:
|
||||
# connect: connection refused (ECONNREFUSED)
|
||||
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
# @static if isinteractive()
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
#
|
||||
# if Sys.islinux() && isinteractive()
|
||||
# image_comparison_facts(:plotlyjs,
|
||||
# skip=[
|
||||
# 2, # animation (skipped for speed)
|
||||
# 25,
|
||||
# 27, # (polar plots) takes very long / not working
|
||||
# 30,
|
||||
# 31, # animation (skipped for speed)
|
||||
# ],
|
||||
# tol=img_tol)
|
||||
# end
|
||||
# end
|
||||
|
||||
|
||||
# InspectDR returns that error on travis:
|
||||
# ERROR: LoadError: InitError: Cannot open display:
|
||||
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
|
||||
@@ -83,16 +87,6 @@ end
|
||||
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "Immerse" begin
|
||||
# @test immerse() == Plots.ImmerseBackend()
|
||||
# @test backend() == Plots.ImmerseBackend()
|
||||
#
|
||||
# # as long as we can plot anything without error, it should be the same as Gadfly
|
||||
# image_comparison_facts(:immerse, only=[1], tol=img_tol)
|
||||
# end
|
||||
|
||||
|
||||
# @testset "PlotlyJS" begin
|
||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||
# @test backend() == Plots.PlotlyJSBackend()
|
||||
@@ -102,19 +96,6 @@ end
|
||||
# end
|
||||
|
||||
|
||||
# @testset "Gadfly" begin
|
||||
# @test gadfly() == Plots.GadflyBackend()
|
||||
# @test backend() == Plots.GadflyBackend()
|
||||
#
|
||||
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
|
||||
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
|
||||
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
|
||||
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
|
||||
#
|
||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], tol=img_tol)
|
||||
# end
|
||||
|
||||
|
||||
|
||||
|
||||
@testset "Axes" begin
|
||||
|
||||
Reference in New Issue
Block a user