Skip to content

Commit

Permalink
integrate UnitfulRecipes into Plots (#4371)
Browse files Browse the repository at this point in the history
* integrate `UnitfulRecipes`

* add authors

* format

* tests: replace `plt` with `pl`

* remove duplicate `AVec` `AMat` - move defs

* rework structure and exports

* reorganize imports

* replace `__init__` calls in tests

* move `using` statements

* add test note

* actually fix 4366

* add authors

Co-authored-by: Jan Weidner <[email protected]>

* fix `ProtectedString` docstring

* cleanup

Co-authored-by: Jan Weidner <[email protected]>
  • Loading branch information
t-bltg and jw3126 authored Sep 27, 2022
1 parent 89c68d9 commit e0c58fb
Show file tree
Hide file tree
Showing 14 changed files with 763 additions and 128 deletions.
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"

[targets]
test = ["Colors", "Distributions", "FileIO", "FilePathsBase", "Gaston", "GeometryBasics", "Gtk", "ImageMagick", "Images", "InspectDR", "LibGit2", "OffsetArrays", "PGFPlotsX", "PlotlyJS", "PlotlyBase", "PyPlot", "PlotlyKaleido", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]
test = ["Colors", "Distributions", "FileIO", "FilePathsBase", "Gaston", "GeometryBasics", "Gtk", "ImageMagick", "Images", "InspectDR", "LibGit2", "OffsetArrays", "PGFPlotsX", "PlotlyJS", "PlotlyBase", "PyPlot", "PlotlyKaleido", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "Unitful", "VisualRegressionTests"]
137 changes: 41 additions & 96 deletions src/Plots.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
module Plots

using Pkg

if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel"))
@eval Base.Experimental.@optlevel 1
end
if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@max_methods"))
@eval Base.Experimental.@max_methods 1
end

using Pkg

const _plots_project = Pkg.Types.read_project(normpath(@__DIR__, "..", "Project.toml"))
const _current_plots_version = _plots_project.version
const _plots_compats = _plots_project.compat

function _check_compat(sim::Module)
sim_str = string(sim)
haskey(_plots_compats, sim_str) || return nothing
Expand All @@ -28,26 +29,42 @@ function _check_compat(sim::Module)
end
end

using Reexport

using Dates, Printf, Statistics, Base64, LinearAlgebra, Random, Unzip
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
using SparseArrays

using FFMPEG

@reexport using RecipesBase
import RecipesBase: plot, plot!, animate, is_explicit, grid
using Base.Meta
@reexport using PlotUtils
using Requires
using Reexport
using Unzip
@reexport using RecipesBase
@reexport using PlotThemes
@reexport using PlotUtils

import RecipesBase: plot, plot!, animate, is_explicit, grid
import RecipesPipeline
import RecipesPipeline:
inverse_scale_func,
datetimeformatter,
AbstractSurface,
group_as_matrix, # for StatsPlots
dateformatter,
timeformatter,
needs_3d_axes,
DefaultsDict,
scale_func,
is_surface,
Formatted,
reset_kw!,
SliceIt,
Surface,
pop_kw!,
Volume,
is3d
import UnicodeFun
import StatsBase
import Downloads
import Showoff
import JSON
import JLFzf

using Requires
import JSON

#! format: off
export
Expand Down Expand Up @@ -142,56 +159,19 @@ ignorenan_extrema(x::AbstractArray{<:AbstractFloat}) = NaNMath.extrema(x)
ignorenan_extrema(x) = Base.extrema(x)

# ---------------------------------------------------------

# to cater for block matrices, Base.transpose is recursive.
# This makes it impossible to create row vectors of String and Symbol with the transpose operator.
# This solves this issue, internally in Plots at least.

# commented out on the insistence of the METADATA maintainers

#Base.transpose(x::Symbol) = x
#Base.transpose(x::String) = x

# ---------------------------------------------------------

import Measures

include("plotmeasures.jl")

using .PlotMeasures
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
# ---------------------------------------------------------

import RecipesPipeline
import RecipesPipeline:
SliceIt,
DefaultsDict,
Formatted,
AbstractSurface,
Surface,
Volume,
is3d,
is_surface,
needs_3d_axes,
group_as_matrix, # for StatsPlots
reset_kw!,
pop_kw!,
scale_func,
inverse_scale_func,
dateformatter,
datetimeformatter,
timeformatter

# Use fixed version of Plotly instead of the latest one for stable dependency
# Ref: https://github.com/JuliaPlots/Plots.jl/pull/2779
const _plotly_min_js_filename = "plotly-2.6.3.min.js"

include("types.jl")
include("utils.jl")
include("colorbars.jl")
include("axes.jl")
include("args.jl")
include("components.jl")
include("legend.jl")
include("consts.jl")
include("themes.jl")
include("plot.jl")
Expand All @@ -206,55 +186,20 @@ include("backends.jl")
include("output.jl")
include("ijulia.jl")
include("fileio.jl")

# Use fixed version of Plotly instead of the latest one for stable dependency
# Ref: https://github.com/JuliaPlots/Plots.jl/pull/2779
const _plotly_min_js_filename = "plotly-2.6.3.min.js"
const CURRENT_BACKEND = CurrentBackend(:none)
const PLOTS_SEED = 1234

include("init.jl")
include("legend.jl")

include("backends/plotly.jl")
include("backends/gr.jl")
include("backends/web.jl")
include("backends/gr.jl")

const PlotOrSubplot = Union{Plot,Subplot}
include("shorthands.jl")

# ---------------------------------------------------------

const CURRENT_BACKEND = CurrentBackend(:none)
const PLOTS_SEED = 1234

using SnoopPrecompile

@precompile_setup begin
n = length(_examples)
imports = sizehint!(Expr[], n)
examples = sizehint!(Expr[], 10n)
for i in setdiff(1:n, _backend_skips[:gr])
_examples[i].external && continue
(imp = _examples[i].imports) === nothing || push!(imports, imp)
func = gensym(string(i))
push!(examples, quote
$func() = begin # evaluate each example in a local scope
# @show $i # debug
$(_examples[i].exprs)
if $i == 1 # only for one example
fn = tempname()
pl = current()
gui(pl)
savefig(pl, "$fn.png")
savefig(pl, "$fn.pdf")
end
nothing
end
$func()
end)
end
withenv("GKSwstype" => "nul") do
@precompile_all_calls begin
eval.(imports)
gr()
eval.(examples)
# eventually eval for another backend ...
end
end
end
include("precompilation.jl")

end
2 changes: 2 additions & 0 deletions src/animation.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using FFMPEG

"Represents an animation object"
struct Animation
dir::String
Expand Down
4 changes: 1 addition & 3 deletions src/backends/pgfplotsx.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import UUIDs: uuid4
import Latexify
import Contour

# FIXME: cannot use `import PGFPlotsX: ...` with @require
const Options = PGFPlotsX.Options
const Table = PGFPlotsX.Table
import .PGFPlotsX: Options, Table

Base.@kwdef mutable struct PGFPlotsXPlot
is_created::Bool = false
Expand Down
45 changes: 28 additions & 17 deletions src/init.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using REPL
using Scratch
using RelocatableFolders
using Scratch
using REPL

const plotly_local_file_path = Ref{Union{Nothing,String}}(nothing)
const BACKEND_PATH_GASTON = @path joinpath(@__DIR__, "backends", "gaston.jl")
Expand All @@ -21,13 +21,30 @@ _plots_defaults() =
Dict{Symbol,Any}()
end

function __init__()
function _plots_theme_defaults()
user_defaults = _plots_defaults()
if haskey(user_defaults, :theme)
theme(pop!(user_defaults, :theme); user_defaults...)
else
default(; user_defaults...)
end
end

function _plots_plotly_defaults()
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global plotly_local_file_path[] =
joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
isfile(plotly_local_file_path[]) || Downloads.download(
"https://cdn.plot.ly/$(_plotly_min_js_filename)",
plotly_local_file_path[],
)
use_local_plotlyjs[] = true
end
use_local_dependencies[] = use_local_plotlyjs[]
end

function __init__()
_plots_theme_defaults()

insert!(
Base.Multimedia.displays,
Expand Down Expand Up @@ -77,6 +94,8 @@ function __init__()
include(BACKEND_PATH_PLOTLYJS)
end

_plots_plotly_defaults()

@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" begin
include(BACKEND_PATH_PYPLOT)
end
Expand All @@ -96,19 +115,6 @@ function __init__()
end
end

if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global plotly_local_file_path[] =
joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
isfile(plotly_local_file_path[]) || Downloads.download(
"https://cdn.plot.ly/$(_plotly_min_js_filename)",
plotly_local_file_path[],
)

use_local_plotlyjs[] = true
end

use_local_dependencies[] = use_local_plotlyjs[]

@require ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" begin
if get(ENV, "PLOTS_IMAGE_IN_TERMINAL", "false") == "true" &&
ImageInTerminal.ENCODER_BACKEND[] == :Sixel
Expand Down Expand Up @@ -153,9 +159,14 @@ function __init__()
# Lists of tuples and GeometryBasics.Points
# --------------------------------------------------------------------
@recipe f(v::AVec{<:GeometryBasics.Point}) = RecipesPipeline.unzip(v)
@recipe f(p::GeometryBasics.Point) = [p]# Special case for 4-tuples in :ohlc series
@recipe f(p::GeometryBasics.Point) = [p] # Special case for 4-tuples in :ohlc series
@recipe f(xyuv::AVec{<:Tuple{R1,R2,R3,R4}}) where {R1,R2,R3,R4} =
get(plotattributes, :seriestype, :path) === :ohlc ?
OHLC[OHLC(t...) for t in xyuv] : RecipesPipeline.unzip(xyuv)
end

@require Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" begin
include("unitful.jl")
@reexport using .UnitfulRecipes
end
end
7 changes: 5 additions & 2 deletions src/plotmeasures.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module PlotMeasures
import Measures
import Measures:

import ..Measures
import ..Measures:
Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h

const BBox = Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h

Expand All @@ -15,4 +17,5 @@ Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.val
Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)

end
37 changes: 37 additions & 0 deletions src/precompilation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using SnoopPrecompile

if get(ENV, "PLOTS_PRECOMPILE", "true") == "true"
@precompile_setup begin
n = length(_examples)
imports = sizehint!(Expr[], n)
examples = sizehint!(Expr[], 10n)
for i in setdiff(1:n, _backend_skips[:gr])
_examples[i].external && continue
(imp = _examples[i].imports) === nothing || push!(imports, imp)
func = gensym(string(i))
push!(examples, quote
$func() = begin # evaluate each example in a local scope
# @show $i # debug
$(_examples[i].exprs)
if $i == 1 # only for one example
fn = tempname()
pl = current()
gui(pl)
savefig(pl, "$fn.png")
savefig(pl, "$fn.pdf")
end
nothing
end
$func()
end)
end
withenv("GKSwstype" => "nul") do
@precompile_all_calls begin
eval.(imports)
gr()
eval.(examples)
# eventually eval for another backend ...
end
end
end
end
1 change: 1 addition & 0 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
end

struct PlaceHolder end
const PlotOrSubplot = Union{Plot,Subplot}

# -----------------------------------------------------------

Expand Down
Loading

0 comments on commit e0c58fb

Please sign in to comment.