Skip to content

Commit

Permalink
Merge pull request #6 from Datax-package/latexify
Browse files Browse the repository at this point in the history
Version 3.0.0
  • Loading branch information
gustaphe authored Feb 20, 2021
2 parents 59b0e7e + d304bcd commit 8dcc70f
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 158 deletions.
12 changes: 7 additions & 5 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
name = "LaTeXDatax"
uuid = "644dedec-337d-45c6-9a86-27a5fed2b77d"
authors = ["David Gustavsson <[email protected]> and contributors"]
version = "2.2.0"

version = "3.0.0"


[deps]
Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
UnitfulLatexify = "45397f5d-5981-4c77-b2b3-fc36d6e9b728"

[compat]
Formatting = "0.4"
Requires = "1.1"
Latexify = "0.14.7"
Unitful = "1.5"
UnitfulLatexify = "1.3.0"
julia = "1"

[extras]
Expand Down
18 changes: 5 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,21 @@ the accompanying package `datax.sty`.

## Usage
```julia
using LaTeXDatax
filename = "datafile.tex"; # default is "data.tex"
using LaTeXDatax, Unitful
a = 25;
b = "Something";
c = (300,"\\mega\\meter\\per\\second");

using Unitful
d = 4.2u"Hz";

@datax a b c d filename
# or, equivalently,
data(a=a, b="Something", c=c, d=d, filename="datafile.tex");
@datax a b=3a c=3e8u"m/s" d="Raw string" filename:="data.tex"
```

```latex
\documentclass{article}
\usepackage{siunitx}
\usepackage[dataxfile=datafile.tex]{datax}
\usepackage[dataxfile=data.tex]{datax}
\begin{document}
The speed of light is \datax{c}.
\end{document}
```

More detailed usage information is in the docstrings of the code, run `?datax`
and `?@datax` in REPL to read them.
More detailed usage information is in the docstrings of the code, run `?@datax`
in REPL to read them.
203 changes: 85 additions & 118 deletions src/LaTeXDatax.jl
Original file line number Diff line number Diff line change
@@ -1,147 +1,114 @@
module LaTeXDatax
using Requires, Formatting
using Unitful, UnitfulLatexify, Latexify

export datax,@datax
export @datax

"""
```julia
datax(...)
@datax
```
Print the arguments to a file readable by pgfkeys (Best for use with the
`datax` LaTeX package). A string will be printed as is, a number will be
wrapped in `siunitx`'s `\\num`, and a tuple `(value::Number, unit::String)` or
a `Unitful` quantity will be wrapped in `\\SI`. If the argument is a `Tuple`
and the first argument is a string, it is used as a c-printf style format
string for the rest of the tuple (overriding the default format set by the
"format" argument). There's also a macro form, `@datax`, which reuses the
variable names from the script.
Print the arguments to a data file to be read by pgfkeys. Best used with the
[`datax` LaTeX package](https://ctan.org/pkg/datax). Variables can be supplied
either by name or as assignments, and meta-arguments are supplied using the
`:=` operator.
The variable names "filename" and "format" cannot be stored, but will instead
be used as the name of the file and the default number format respectively.
The meta-arguments include all the keyword arguments from `Latexify.jl` and
`UnitfulLatexify.jl` (for instance `unitformat := :siunitx`, `fmt := "%.2e"`),
as well as a few extra:
# Meta-arguments
* `filename`: The path to a file that will be written.
* `io`: an `IO` object to write to instead of a file. Overrides the `filename`
argument. If neither this nor `filename` is given, `stdout` is used.
* `permissions`: Defaults to `"w"`. Can be given as `"a"` to append to a file
instead of overwriting. Only meaningful with a `filename` argument.
# Examples
```julia
datax(a=2,b=1.24,c="hi",d=(24,"\\meter"),e=15u"kg/s^2")
```
Save the given variables in siunitx form.
julia> a = 2;
julia> b = 3.2u"m";
julia> @datax a b c=3*a d=27 unitformat:=:siunitx
\\pgfkeyssetvalue{/datax/a}{\\num{2}}
\\pgfkeyssetvalue{/datax/b}{\\SI{3.2}{\\meter}}
\\pgfkeyssetvalue{/datax/c}{\\num{6}}
\\pgfkeyssetvalue{/datax/d}{\\num{27}}
```julia
datax(lambda=612.2u"nm",filename="other.tex",format="%.4e")
datax(lambda=("%.4e",612.2,"\\nano\\meter"),filename="other.tex")
```
Save just the variable lambda, in the file "other.tex", in scientific notation
with 4 digits of accuracy. The two lines are equivalent.
"""
function datax(;filename="data.tex",format="%.4g",overwrite=true,kwargs...)
datax(Dict(kwargs);filename,format,overwrite)
macro datax(args...)
esc(datax_helper(args...))
end

function datax(d::Dict{Symbol,<:Any};filename="data.tex",format::String="%.4g",overwrite=true)
filename = pop!(d,:filename,filename)
format = pop!(d,:format,format)
overwrite = pop!(d,:overwrite,overwrite)
permission = overwrite ? "w" : "a"
open(filename,permission) do f
println(f,"% Autogenerated by LaTeXDatax.jl, will be overwritten")
for (k,v) in d
print(f,"\\pgfkeyssetvalue{/datax/$k}{")
printdata(f,v,format)
print(f,"}\n")
function datax_helper(args...)
metaargs = Expr[]
names = Symbol[]
values = Any[]
for a in args
if a isa Symbol
push!(names, a)
push!(values, a)
continue
end
end
end
if a.head == :(=)
push!(names, a.args[1])
push!(values, a.args[2])
continue

"""
```julia
@datax ...
```
Print the arguments to a file readable by pgfkeys (Best for use with the
`datax` LaTeX package). Like the `datax()` function, but use the variables'
names.
end
if a.head == :(:=)
push!(metaargs, Expr(:kw,a.args[1],a.args[2]))
continue
end
error("I don't know what to do with argument $a")
end

# Examples
```julia
a=2;
b=3.2u"m";
c="hi";
filename="datafile.tex";
format="%.2g";
@datax a b c filename format
```
"""
macro datax(args...)
esc(datax_helper(args...))
end
function datax_helper(args...)
names = Expr(:vect, QuoteNode.(args)...)
values = Expr(:vect, args...)
names = Expr(:tuple, QuoteNode.(names)...)
values = Expr(:tuple, values...)
quote
datax(Dict($names .=> $values))
LaTeXDatax.datax($names,$values;$(metaargs...))
nothing
end
end

printdata(f::IO,v::String,fmt::String) = print(f,v)
printdata(f::IO,v::Number,fmt::String) = print(f,"\\num{",sprintf1(fmt,v),"}")
printdata(f::IO,v::AbstractArray{<:Number},fmt::String) = print(f,"\\numlist{",prod(sprintf1.(fmt,v).*";"),"}")
printdata(f::IO,v::Tuple{<:Number,String},fmt::String) = print(f,"\\SI{",sprintf1(fmt,v[1]),"}{",v[2],"}")
printdata(f::IO,v::Tuple{AbstractArray{<:Number},String},fmt::String) = print(f,
"\\SIlist{",
prod(
sprintf1.(fmt,v[1]).*";")
,"}{",
v[2],
"}"
)
printdata(f::IO,v::Tuple{String,Vararg},fmt::String) = printdata(f,length(v)>2 ? v[2:end] : v[2], v[1])

function __init__()
@require Unitful="1986cc42-f94f-5a68-af5c-568840ba703d" begin

function printdata(f::IO,v::Unitful.Quantity,fmt::String)
print(f,"\\SI{"*sprintf1(fmt,v.val)*"}{")
siunitxprint(f,Unitful.unit(v))
print(f,"}")
end
function printdata(f::IO,v::AbstractArray{T},fmt::String) where T<:Unitful.Quantity
print(f,"\\SIlist{"*prod(sprintf1.(fmt,Unitful.ustrip(v)).*";")*"}{")
siunitxprint(f,Unitful.unit(T))
print(f,"}")
end
function datax(names, values; kwargs...)
if haskey(kwargs, :io)
datax(kwargs[:io], names, values; kwargs...)
return nothing
end
if haskey(kwargs, :filename)
datax(kwargs[:filename], names, values; kwargs...)
return nothing
end
datax(stdout, names, values; kwargs...)
return nothing
end

function siunitxprint(f::IO,u::Unitful.FreeUnits)
prefixes = Dict(
-24 => "\\yocto",
-21 => "\\zepto",
-18 => "\\atto",
-15 => "\\femto",
-12 => "\\pico",
-9 => "\\nano",
-6 => "\\micro",
-3 => "\\milli",
-2 => "\\centi",
-1 => "\\deci",
0 => "",
1 => "\\deka",
2 => "\\hecto",
3 => "\\kilo",
6 => "\\mega",
9 => "\\giga",
12 => "\\tera",
15 => "\\peta",
18 => "\\exa",
21 => "\\zetta",
24 => "\\yotta"
)
for p in typeof(u).parameters[1]
p.power<0 && print(f,"\\per")
iszero(p.tens) || print(f,prefixes[p.tens])
print(f,"\\$(lowercase(String(Unitful.name(p))))")
abs(p.power)==1 || print(f,"\\tothe$(Int64(abs(p.power)))")
end
end
datax(io::IO, names, values; kwargs...) = printkeyval.(Ref(io),names,values; kwargs...)

function datax(filename::String, names, values; permissions="w", kwargs...)
if haskey(kwargs,:overwrite)
if kwargs[:overwrite]
permissions = "w"
else
permissions = "a"
end
end
open(filename, permissions) do io
permissions == "w" && println(io, "% Autogenerated by LaTeXDatax.jl, will be overwritten")
datax(io, names, values; kwargs...)
end
end

function printkeyval(io::IO, name, value; kwargs...)
print(io, "\\pgfkeyssetvalue{/datax/", name, "}{")
printdata(io, value; kwargs...)
print(io, "}\n")
return nothing
end

printdata(io::IO, v::String; kwargs...) = print(io, v)
printdata(io::IO, v::Number; kwargs...) = print(io, latexify(v*u"one"; kwargs...))
printdata(io::IO, v; kwargs...) = print(io, latexify(v; kwargs...))

end # module
40 changes: 18 additions & 22 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,28 @@ using Test
@testset "LaTeXDatax.jl" begin
io = IOBuffer();

# Basic printing
LaTeXDatax.printdata(io,"String","%.4g")
# Basic data printing
LaTeXDatax.printdata(io,"String")
@test String(take!(io)) == "String"
LaTeXDatax.printdata(io,4.1,"%.4g")
@test String(take!(io)) == "\\num{4.1}"
LaTeXDatax.printdata(io,[1.0,2.4,3.0],"%.4g")
@test String(take!(io)) == "\\numlist{1;2.4;3;}"

# Print units
LaTeXDatax.printdata(io,(1.0,"\\meter"),"%.4g")
@test String(take!(io)) == "\\SI{1}{\\meter}"
LaTeXDatax.printdata(io,([1,2,3],"\\kilogram"),"%.4g")
@test String(take!(io)) == "\\SIlist{1;2;3;}{\\kilogram}"
LaTeXDatax.printdata(io,1.25)
@test String(take!(io)) == "\$1.25\$"

# Format strings
LaTeXDatax.printdata(io,pi,"%.3g")
LaTeXDatax.printdata(io,3.141592; fmt="%.2f", unitformat=:siunitx)
@test String(take!(io)) == "\\num{3.14}"
LaTeXDatax.printdata(io,("%.2g",pi),"%.4g")
@test String(take!(io)) == "\\num{3.1}"
LaTeXDatax.printdata(io,("%.5g",pi,"\\liter"),"%.4g")
@test String(take!(io)) == "\\SI{3.1416}{\\liter}"

# Unitful
LaTeXDatax.printdata(io,2u"m","%.4g")
@test String(take!(io)) == "\\SI{2}{\\meter}"
LaTeXDatax.printdata(io,[1.4,2.8]u"g/J","%.4g")
@test String(take!(io)) == "\\SIlist{1.4;2.8;}{\\gram\\per\\joule}"
# keyval printing
LaTeXDatax.printkeyval(io, :a, 612.2u"nm")
@test String(take!(io)) == "\\pgfkeyssetvalue{/datax/a}{\$612.2\\;\\mathrm{nm}\$}\n"

# complete macro
a = 2;
b = 3.2u"m";
@datax a b c=3*a d=27 unitformat:=:siunitx io:=io
@test String(take!(io)) == """
\\pgfkeyssetvalue{/datax/a}{\\num{2}}
\\pgfkeyssetvalue{/datax/b}{\\SI{3.2}{\\meter}}
\\pgfkeyssetvalue{/datax/c}{\\num{6}}
\\pgfkeyssetvalue{/datax/d}{\\num{27}}
"""
end

2 comments on commit 8dcc70f

@gustaphe
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/30484

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v3.0.0 -m "<description of version>" 8dcc70f7720953a5d5b14d871b346c230f08ccb7
git push origin v3.0.0

Please sign in to comment.