Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ You can control the formatting of numbers by passing any of the following to the
- a formatter supplied by Latexify.jl, for example `fmt = FancyNumberFormatter(2)` (thanks to @simeonschaub). You can pass any of these formatters an integer argument which specifies how many significant digits you want.
- `FancyNumberFormatter()` replaces the exponent notation, from `1.2e+3` to `1.2 \cdot 10^3`.
- `StyledNumberFormatter()` replaces the exponent notation, from `1.2e+3` to `1.2 \mathrm{e} 3`.
- `SiunitxNumberFormatter()` uses the `siunitx` package's `\num`, so all the formatting is offloaded on the `\LaTeX` engine. Formatting arguments can be supplied as a string to the keyword argument `format_options`. If your `siunitx` installation is version 2 or older, use the keyword argument `version=2` to replace `\num` by `\si`.



Examples:
```@example main
latexify(12345.678; fmt="%.1e")
```
$1.2e+04$

```@example main
latexify([12893.1 1.328e2; "x/y" 7832//2378]; fmt=FancyNumberFormatter(3))
Expand All @@ -112,6 +112,10 @@ using Format
latexify([12893.1 1.328e2]; fmt=x->format(round(x, sigdigits=2), autoscale=:metric))
```

```@example main
str = latexify(12345.678; fmt=SiunitxNumberFormatter(format_options="round-mode=places,round-precision=1", version=3))
replace(string(str), "\$"=>"`") # hide
```

## Automatic copying to clipboard
The strings that you would see when using print on any of the above functions can be automatically copied to the clipboard if you so specify.
Expand Down
4 changes: 4 additions & 0 deletions docs/src/tutorials/latextabular.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ $\frac{x}{y}$ & $1.0$\\
$y^{n}$ & $\alpha\left( x \right)$\\
\end{tabular}
```

The adjustments can be set per column by providing a vector like `[:c, :l, :r]`.
If you want to use the `S` column type from `siunitx`, set `latex=false, adjustment=:S`.
Some post-adjustment may be necessary.
2 changes: 1 addition & 1 deletion src/Latexify.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export latexify, md, copy_to_clipboard, auto_display, set_default, get_default,
## Allow some backwards compatibility until its time to deprecate.
export latexequation, latexarray, latexalign, latexraw, latexinline, latextabular, mdtable

export StyledNumberFormatter, FancyNumberFormatter
export StyledNumberFormatter, FancyNumberFormatter, SiunitxNumberFormatter

COPY_TO_CLIPBOARD = false
function copy_to_clipboard(x::Bool)
Expand Down
19 changes: 13 additions & 6 deletions src/latextabular.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,28 @@ function _latextabular(arr::AbstractMatrix; latex::Bool=true, booktabs::Bool=fal

(rows, columns) = size(arr)

if adjustment isa AbstractArray
adjustmentstring = join(adjustment)
else
adjustmentstring = string(adjustment)^columns
if ~isa(adjustment, AbstractArray)
adjustment = fill(adjustment, columns)
end
adjustmentstring = join(adjustment)
str = "\\begin{tabular}{$adjustmentstring}\n"

if booktabs
str *= "\\toprule\n"
end

formatter = get(kwargs, :fmt, nothing)
if formatter isa String
formatter = PrintfNumberFormatter(formatter)
end
if formatter isa SiunitxNumberFormatter && any(==(:S), adjustment)
# Do not format cell contents, "S" column type handles it
formatter = string
end

if latex
arr = latexinline.(arr; kwargs...)
elseif haskey(kwargs, :fmt)
formatter = kwargs[:fmt] isa String ? PrintfNumberFormatter(kwargs[:fmt]) : kwargs[:fmt]
elseif ~isnothing(formatter)
arr = map(x -> x isa Number ? formatter(x) : x, arr)
end

Expand Down
45 changes: 44 additions & 1 deletion src/numberformatters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,54 @@ struct FancyNumberFormatter <: AbstractNumberFormatter
exponent_format::SubstitutionString=s"\g<mantissa> \\cdot 10^{\g<sign_exp>\g<mag_exp>}") = new(fmt, Format.generate_formatter(fmt), exponent_format)
end

FancyNumberFormatter(fmt::String, mult_symbol) =
FancyNumberFormatter(fmt::String, mult_symbol) =
FancyNumberFormatter(fmt, SubstitutionString("\\g<mantissa> $(escape_string(mult_symbol)) 10^{\\g<sign_exp>\\g<mag_exp>}"))
FancyNumberFormatter(significant_digits, mult_symbol="\\cdot") =
FancyNumberFormatter("%.$(significant_digits)g", mult_symbol)


(f::FancyNumberFormatter)(x::AbstractFloat) = replace(f.f(x), float_regex => f.exponent_format)
(f::FancyNumberFormatter)(x::Unsigned) = "\\mathtt{0x$(string(x; base=16, pad=2sizeof(x)))}"

struct SiunitxNumberFormatter <: AbstractNumberFormatter
format_options::String
version::Int
end
function SiunitxNumberFormatter(;format_options="", version=3)
if ~isempty(format_options) && (~startswith(format_options, '[') || ~endswith(format_options, ']'))
format_options = "[$format_options]"
end
SiunitxNumberFormatter(format_options, version)
end

function (f::SiunitxNumberFormatter)(x::Number)
return "\\$(siunitxcommand(:number, f.version))$(f.format_options){$x}"
end
function (f::SiunitxNumberFormatter)(x::Vector{<:Number})
return "\\$(siunitxcommand(:numberlist, f.version))$(f.format_options){$(join(x,';'))}"
end
function (f::SiunitxNumberFormatter)(x::AbstractRange{<:Number})
return "\\$(siunitxcommand(:numberrange, f.version))$(f.format_options){$(x.start)}{$(x.stop)}"
end

function siunitxcommand(purpose, version)
if version <= 2
purpose === :number && return "si"
purpose === :quantity && return "SI"
purpose === :numberrange && return "sirange"
purpose === :quantityrange && return "SIrange"
purpose === :numberlist && return "silist"
purpose === :quantitylist && return "SIlist"
purpose === :numberproduct && return "siproduct"
purpose === :quantityproduct && return "SIproduct"
end
purpose === :number && return "num"
purpose === :quantity && return "qty"
purpose === :numberrange && return "numrange"
purpose === :quantityrange && return "qtyrange"
purpose === :numberlist && return "numlist"
purpose === :quantitylist && return "qtylist"
purpose === :numberproduct && return "numproduct"
purpose === :quantityproduct && return "qtyproduct"
throw(ArgumentError("Purpose $purpose not implemented"))
end
9 changes: 7 additions & 2 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ add_brackets(ex::Expr, vars) = postwalk(x -> x in vars ? "\\left[ $(convert_subs
add_brackets(arr::AbstractArray, vars) = [add_brackets(element, vars) for element in arr]
add_brackets(s::Any, vars) = s

default_packages(s) = vcat(["amssymb", "amsmath", "unicode-math"], occursin("\\ce{", s) ? ["mhchem"] : [])
default_packages(s) = vcat(
["amssymb", "amsmath", "unicode-math"],
occursin("\\ce{", s) ? ["mhchem"] : [],
any(x->occursin(prod(x), s), Iterators.product(["\\si", "\\SI", "\\num", "\\qty"], ["{", "range{", "list{", "product{"])) ? ["siunitx"] : [],
)

function _writetex(s::LaTeXString;
name=tempname(),
Expand Down Expand Up @@ -154,7 +158,8 @@ function render(s::LaTeXString, mime::MIME"image/png";
# prefer tex -> pdf -> png instead
if convert === :gs
aux_mime = MIME("application/pdf")
cmd = `gs -sDEVICE=pngalpha -dTextAlphaBits=4 -r$dpi -o $name.$ext $aux_name.pdf`
ghostscript_command = get(ENV, "GHOSTSCRIPT", "gs")
cmd = `$ghostscript_command -sDEVICE=pngalpha -dTextAlphaBits=4 -r$dpi -o $name.$ext $aux_name.pdf`
elseif convert === :dvipng
aux_mime = MIME("application/x-dvi")
deb = debug ? [] : ["-q"]
Expand Down
18 changes: 18 additions & 0 deletions test/latextabular_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,21 @@ $a$ & $\frac{x}{k + x}$\\
$b$ & $x - y$\\
\end{tabular}
", "\r\n"=>"\n")

@test latexify(d; env=:tabular, latex=false, fmt=SiunitxNumberFormatter()) == replace(
raw"\begin{tabular}{cc}
A & B\\
\num{11} & X\\
\num{12} & Y\\
\num{13} & Z\\
\end{tabular}
", "\r\n"=>"\n")

@test latexify(d; env=:tabular, latex=false, fmt=SiunitxNumberFormatter(), adjustment=:S) == replace(
raw"\begin{tabular}{SS}
A & B\\
11 & X\\
12 & Y\\
13 & Z\\
\end{tabular}
", "\r\n"=>"\n")
28 changes: 28 additions & 0 deletions test/numberformatters_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,31 @@ xne = -23.4728979e-7
y = 0xf43

@test StyledNumberFormatter()(y) == FancyNumberFormatter()(y) == "\\mathtt{0x0f43}"

@test SiunitxNumberFormatter()(x) == "\\num{-2.34728979e8}"
@test SiunitxNumberFormatter(version=2)(x) == "\\si{-2.34728979e8}"
@test SiunitxNumberFormatter(format_options="something")(x) == "\\num[something]{-2.34728979e8}"
@test SiunitxNumberFormatter(format_options="[something]")(x) == "\\num[something]{-2.34728979e8}"

@test SiunitxNumberFormatter()([1,2,4]) == "\\numlist{1;2;4}"
@test SiunitxNumberFormatter()(1:4) == "\\numrange{1}{4}"

@test Latexify.siunitxcommand(:number, 2) == "si"
@test Latexify.siunitxcommand(:quantity, 2) == "SI"
@test Latexify.siunitxcommand(:numberrange, 2) == "sirange"
@test Latexify.siunitxcommand(:quantityrange, 2) == "SIrange"
@test Latexify.siunitxcommand(:numberlist, 2) == "silist"
@test Latexify.siunitxcommand(:quantitylist, 2) == "SIlist"
@test Latexify.siunitxcommand(:numberproduct, 2) == "siproduct"
@test Latexify.siunitxcommand(:quantityproduct, 2) == "SIproduct"

@test Latexify.siunitxcommand(:number, 3) == "num"
@test Latexify.siunitxcommand(:quantity, 3) == "qty"
@test Latexify.siunitxcommand(:numberrange, 3) == "numrange"
@test Latexify.siunitxcommand(:quantityrange, 3) == "qtyrange"
@test Latexify.siunitxcommand(:numberlist, 3) == "numlist"
@test Latexify.siunitxcommand(:quantitylist, 3) == "qtylist"
@test Latexify.siunitxcommand(:numberproduct, 3) == "numproduct"
@test Latexify.siunitxcommand(:quantityproduct, 3) == "qtyproduct"

@test_throws ArgumentError Latexify.siunitxcommand(:nonsense, 1)
Loading