Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate UnitfulRecipes into Plots #4371

Merged
merged 15 commits into from
Sep 27, 2022
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