Skip to content

Commit

Permalink
add UnitfulExt
Browse files Browse the repository at this point in the history
  • Loading branch information
t-bltg committed Feb 5, 2023
1 parent 3f92541 commit adc63db
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 112 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [4.0] - 2023-02-xx
### Changed
- Rework conditional dependencies (`Unitful`, `FreeType`, `FileIO`) through weak deps to improve latency

## [3.3] - 2022-11-17
### Added
- Group digits on integer values (thousands) for readability (configured using `thousands_separator`).
Expand Down
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[compat]
ColorSchemes = "^3.19"
Expand All @@ -43,10 +42,12 @@ julia = "1.6"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
FreeType = "b38be410-82b0-50bf-ab77-7b57e271db43"
ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[extensions]
FreeTypeExt = ["FileIO", "FreeType"]
ImageInTerminalExt = "ImageInTerminal"
UnitfulExt = "Unitful"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Expand All @@ -61,6 +62,7 @@ StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[targets]
test = ["Aqua", "DataFrames", "FileIO", "FreeType", "ImageInTerminal", "ImageMagick", "Random", "ReferenceTests", "StableRNGs", "Test", "TestImages", "TimerOutputs"]
test = ["Aqua", "DataFrames", "FileIO", "FreeType", "ImageInTerminal", "ImageMagick", "Random", "ReferenceTests", "StableRNGs", "Test", "TestImages", "TimerOutputs", "Unitful"]
34 changes: 17 additions & 17 deletions ext/FreeTypeExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,6 @@ fallback_fonts() =

const FT_FONTS = Dict{String,FTFont}()

function UnicodePlots.get_font_face(font = nothing, fallback = fallback_fonts())
face = nothing
for name filter(!isnothing, (font, "JuliaMono", fallback...))
if (face = get(FT_FONTS, name, nothing)) nothing
if (ft = find_font(name)) nothing
face = FT_FONTS[name] = ft
break # found new font, cache and return it
end
else
break # found in cache
end
end
face
end

UnicodePlots.save_image(args...; kw...) = FileIO.save(args...; kw...)

"""
Match a font using the user-specified search string. Each part of the search string
is searched in the family name first which has to match once to include the font
Expand Down Expand Up @@ -492,4 +475,21 @@ function __init__()
nothing
end

function UnicodePlots.get_font_face(font = nothing, fallback = fallback_fonts())
face = nothing
for name filter(!isnothing, (font, "JuliaMono", fallback...))
if (face = get(FT_FONTS, name, nothing)) nothing
if (ft = find_font(name)) nothing
face = FT_FONTS[name] = ft
break # found new font, cache and return it
end
else
break # found in cache
end
end
face
end

UnicodePlots.save_image(args...; kw...) = FileIO.save(args...; kw...)

end # module
2 changes: 1 addition & 1 deletion ext/ImageInTerminalExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ end
UnicodePlots.imageplot(img::AbstractArray{<:Colorant}; kw...) =
UnicodePlots.Plot(UnicodePlots.ImageGraphics(img); border = :corners, kw...)

end
end # module
84 changes: 84 additions & 0 deletions ext/UnitfulExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
module UnitfulExt

import UnicodePlots
import UnicodePlots: KEYWORDS, Plot, Canvas
@static if isdefined(Base, :get_extension)
import Unitful: Quantity, RealOrRealQuantity, ustrip, unit
else
import ..Unitful: Quantity, RealOrRealQuantity, ustrip, unit
end

function unit_str(x, fancy)
io = IOContext(PipeBuffer(), :fancy_exponent => fancy)
show(io, unit(x))
read(io, String)
end

unit_label(label::AbstractString, unit::AbstractString) =
(lab_strip = rstrip(label)) |> isempty ? unit : "$lab_strip ($unit)"
unit_label(label::AbstractString, unit::Nothing) = rstrip(label)

number_unit(x::Union{AbstractVector,Number}, args...) = x, nothing
number_unit(x::AbstractVector{<:Quantity}, fancy = true) =
ustrip.(x), unit_str(first(x), fancy)
number_unit(x::Quantity, fancy = true) = ustrip(x), unit_str(x, fancy)

# ---------------------------------------------------------------------------- #
# lineplot
function UnicodePlots.lineplot(
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
unicode_exponent::Bool = KEYWORDS.unicode_exponent,
xlabel = KEYWORDS.xlabel,
ylabel = KEYWORDS.ylabel,
kw...,
)
x, ux = number_unit(x, unicode_exponent)
y, uy = number_unit(y, unicode_exponent)
UnicodePlots.lineplot(
ustrip.(x),
ustrip.(y);
xlabel = unit_label(xlabel, ux),
ylabel = unit_label(ylabel, uy),
unicode_exponent,
kw...,
)
end

UnicodePlots.lineplot!(
plot::Plot{<:Canvas},
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
kw...,
) = UnicodePlots.lineplot!(plot, ustrip.(x), ustrip.(y); kw...)

# ---------------------------------------------------------------------------- #
# scatterplot
function UnicodePlots.scatterplot(
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
unicode_exponent::Bool = KEYWORDS.unicode_exponent,
xlabel = KEYWORDS.xlabel,
ylabel = KEYWORDS.ylabel,
kw...,
)
x, ux = number_unit(x, unicode_exponent)
y, uy = number_unit(y, unicode_exponent)
UnicodePlots.scatterplot(
ustrip.(x),
ustrip.(y);
xlabel = unit_label(xlabel, ux),
ylabel = unit_label(ylabel, uy),
unicode_exponent,
kw...,
)
end

UnicodePlots.scatterplot!(
plot::Plot{<:Canvas},
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
kw...,
) = UnicodePlots.scatterplot!(plot, ustrip.(x), ustrip.(y); kw...)

end # module
17 changes: 9 additions & 8 deletions src/UnicodePlots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ using Crayons
using Printf
using Dates

import Unitful: Quantity, RealOrRealQuantity, ustrip, unit
import StatsBase: Histogram, fit, percentile, sturges
import SparseArrays: AbstractSparseMatrix, findnz
import Base: RefValue

import MarchingCubes
import ColorSchemes
import Requires
import NaNMath
import Contour

Expand Down Expand Up @@ -112,7 +110,7 @@ include("interface/boxplot.jl")
include("interface/polarplot.jl")
include("interface/imageplot.jl")

isdefined(Base, :get_extension) || import Requires
isdefined(Base, :get_extension) || import Requires: @require

function __init__()
if (terminal_24bit() || forced_24bit()) && !forced_8bit()
Expand All @@ -123,14 +121,17 @@ function __init__()
faintcolors!()
end
@static if !isdefined(Base, :get_extension) # COV_EXCL_LINE
Requires.@require ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" include(
"../ext/ImageInTerminalExt.jl",
@require ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" include(
normpath(@__DIR__, "..", "ext", "ImageInTerminalExt.jl"),
)
Requires.@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
Requires.@require FreeType = "b38be410-82b0-50bf-ab77-7b57e271db43" begin
include("../ext/FreeTypeExt.jl")
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
@require FreeType = "b38be410-82b0-50bf-ab77-7b57e271db43" begin
include(normpath(@__DIR__, "..", "ext", "FreeTypeExt.jl"))
end
end
@require Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" include(
normpath(@__DIR__, "..", "ext", "UnitfulExt.jl"),
)
end
nothing
end
Expand Down
16 changes: 0 additions & 16 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -377,22 +377,6 @@ ceil_base(x, b) = round_base(x, b, RoundUp)
round_base(x::T, b, ::RoundingMode{:Down}) where {T} = T(b^floor(log(b, x)))
round_base(x::T, b, ::RoundingMode{:Up}) where {T} = T(b^ceil(log(b, x)))

function unit_str(x, fancy)
io = IOContext(PipeBuffer(), :fancy_exponent => fancy)
show(io, unit(x))
read(io, String)
end

number_unit(x::AbstractVector{<:Quantity}, fancy = true) =
ustrip.(x), unit_str(first(x), fancy)
number_unit(x::Quantity, fancy = true) = ustrip(x), unit_str(x, fancy)
number_unit(x::AbstractVector, args...) = x, nothing
number_unit(x::Number, args...) = x, nothing

unit_label(label::AbstractString, unit::AbstractString) =
(lab_strip = rstrip(label)) |> isempty ? unit : "$lab_strip ($unit)"
unit_label(label::AbstractString, unit::Nothing) = rstrip(label)

function superscript(s::AbstractString)::String
v = collect(s)
for (i, k) enumerate(v)
Expand Down
29 changes: 0 additions & 29 deletions src/interface/lineplot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,35 +183,6 @@ end
lineplot!(plot::Plot{<:Canvas}, x::AbstractVector{<:TimeType}, y::AbstractVector; kw...) =
lineplot!(plot, Dates.value.(x), y; kw...)

# ---------------------------------------------------------------------------- #
# Unitful
function lineplot(
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
unicode_exponent::Bool = KEYWORDS.unicode_exponent,
xlabel = KEYWORDS.xlabel,
ylabel = KEYWORDS.ylabel,
kw...,
)
x, ux = number_unit(x, unicode_exponent)
y, uy = number_unit(y, unicode_exponent)
lineplot(
ustrip.(x),
ustrip.(y);
xlabel = unit_label(xlabel, ux),
ylabel = unit_label(ylabel, uy),
unicode_exponent,
kw...,
)
end

lineplot!(
plot::Plot{<:Canvas},
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
kw...,
) = lineplot!(plot, ustrip.(x), ustrip.(y); kw...)

# ---------------------------------------------------------------------------- #
# slope and intercept
function lineplot!(plot::Plot{<:Canvas}, intercept::Number, slope::Number; kw...)
Expand Down
29 changes: 0 additions & 29 deletions src/interface/scatterplot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,32 +132,3 @@ function scatterplot!(plot::Plot{<:Canvas}, x::AbstractVector, y::AbstractMatrix
end
plot
end

# ---------------------------------------------------------------------------- #
# Unitful
function scatterplot(
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
unicode_exponent::Bool = KEYWORDS.unicode_exponent,
xlabel = KEYWORDS.xlabel,
ylabel = KEYWORDS.ylabel,
kw...,
)
x, ux = number_unit(x, unicode_exponent)
y, uy = number_unit(y, unicode_exponent)
scatterplot(
ustrip.(x),
ustrip.(y);
xlabel = unit_label(xlabel, ux),
ylabel = unit_label(ylabel, uy),
unicode_exponent,
kw...,
)
end

scatterplot!(
plot::Plot{<:Canvas},
x::AbstractVector{<:RealOrRealQuantity},
y::AbstractVector{<:Quantity};
kw...,
) = scatterplot!(plot, ustrip.(x), ustrip.(y); kw...)
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using ImageInTerminal, FreeType, FileIO # weak deps, or @require
using ImageInTerminal, FreeType, FileIO, Unitful # weak deps, or @require
using UnicodePlots, Test

import UnicodePlots: lines!, points!, pixel!, nrows, ncols
Expand Down
22 changes: 14 additions & 8 deletions test/tst_common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,20 @@ end
@test UnicodePlots.keywords() isa String
end

const UE = if isdefined(Base, :get_extension)
Base.get_extension(UnicodePlots, :UnitfulExt)
else
UnicodePlots.UnitfulExt
end

@testset "units" begin
x = [1.0, 2.0, 3.0]
@test UnicodePlots.number_unit(x) == (x, nothing)
@test UnicodePlots.number_unit(1) == (1, nothing)
@test UnicodePlots.number_unit(x * u"°C") == (x, "°C")
@test UnicodePlots.number_unit(1u"°C") == (1, "°C")

@test UnicodePlots.unit_label(" fancy label ", "Hz") == " fancy label (Hz)"
@test UnicodePlots.unit_label(" ", "dB") == "dB"
@test UnicodePlots.unit_label(" no units ", nothing) == " no units"
@test UE.number_unit(x) == (x, nothing)
@test UE.number_unit(1) == (1, nothing)
@test UE.number_unit(x * u"°C") == (x, "°C")
@test UE.number_unit(1u"°C") == (1, "°C")

@test UE.unit_label(" fancy label ", "Hz") == " fancy label (Hz)"
@test UE.unit_label(" ", "dB") == "dB"
@test UE.unit_label(" no units ", nothing) == " no units"
end
7 changes: 6 additions & 1 deletion test/tst_quality.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
@testset "Aqua" begin
# JuliaTesting/Aqua.jl/issues/77
Aqua.test_all(UnicodePlots; ambiguities = false, project_toml_formatting = false)
Aqua.test_all(
UnicodePlots;
ambiguities = false,
project_toml_formatting = false, # issues since weak deps
stale_deps = !isdefined(Base, :get_extension), # issue with `Requires` not used when weak deps are enabled
)
Aqua.test_ambiguities(UnicodePlots)
end

0 comments on commit adc63db

Please sign in to comment.