|
1 | 1 | module LaTeXDatax |
2 | | -using Requires, Formatting |
| 2 | +using Unitful, UnitfulLatexify, Latexify |
3 | 3 |
|
4 | | -export datax,@datax |
| 4 | +export @datax |
5 | 5 |
|
6 | 6 | """ |
7 | 7 | ```julia |
8 | | -datax(...) |
| 8 | +@datax |
9 | 9 | ``` |
10 | 10 |
|
11 | | -Print the arguments to a file readable by pgfkeys (Best for use with the |
12 | | -`datax` LaTeX package). A string will be printed as is, a number will be |
13 | | -wrapped in `siunitx`'s `\\num`, and a tuple `(value::Number, unit::String)` or |
14 | | -a `Unitful` quantity will be wrapped in `\\SI`. If the argument is a `Tuple` |
15 | | -and the first argument is a string, it is used as a c-printf style format |
16 | | -string for the rest of the tuple (overriding the default format set by the |
17 | | -"format" argument). There's also a macro form, `@datax`, which reuses the |
18 | | -variable names from the script. |
| 11 | +Print the arguments to a data file to be read by pgfkeys. Best used with the |
| 12 | +[`datax` LaTeX package](https://ctan.org/pkg/datax). Variables can be supplied |
| 13 | +either by name or as assignments, and meta-arguments are supplied using the |
| 14 | +`:=` operator. |
19 | 15 |
|
20 | | -The variable names "filename" and "format" cannot be stored, but will instead |
21 | | -be used as the name of the file and the default number format respectively. |
| 16 | +The meta-arguments include all the keyword arguments from `Latexify.jl` and |
| 17 | +`UnitfulLatexify.jl` (for instance `unitformat := :siunitx`, `fmt := "%.2e"`), |
| 18 | +as well as a few extra: |
| 19 | +
|
| 20 | +# Meta-arguments |
| 21 | +* `filename`: The path to a file that will be written. |
| 22 | +* `io`: an `IO` object to write to instead of a file. Overrides the `filename` |
| 23 | + argument. If neither this nor `filename` is given, `stdout` is used. |
| 24 | +* `permissions`: Defaults to `"w"`. Can be given as `"a"` to append to a file |
| 25 | + instead of overwriting. Only meaningful with a `filename` argument. |
22 | 26 |
|
23 | 27 | # Examples |
24 | 28 | ```julia |
25 | | -datax(a=2,b=1.24,c="hi",d=(24,"\\meter"),e=15u"kg/s^2") |
26 | | -``` |
27 | | -Save the given variables in siunitx form. |
| 29 | +julia> a = 2; |
| 30 | +julia> b = 3.2u"m"; |
| 31 | +julia> @datax a b c=3*a d=27 unitformat:=:siunitx |
| 32 | +\\pgfkeyssetvalue{/datax/a}{\\num{2}} |
| 33 | +\\pgfkeyssetvalue{/datax/b}{\\SI{3.2}{\\meter}} |
| 34 | +\\pgfkeyssetvalue{/datax/c}{\\num{6}} |
| 35 | +\\pgfkeyssetvalue{/datax/d}{\\num{27}} |
28 | 36 |
|
29 | | -```julia |
30 | | -datax(lambda=612.2u"nm",filename="other.tex",format="%.4e") |
31 | | -datax(lambda=("%.4e",612.2,"\\nano\\meter"),filename="other.tex") |
32 | 37 | ``` |
33 | | -Save just the variable lambda, in the file "other.tex", in scientific notation |
34 | | -with 4 digits of accuracy. The two lines are equivalent. |
35 | 38 | """ |
36 | | -function datax(;filename="data.tex",format="%.4g",overwrite=true,kwargs...) |
37 | | - datax(Dict(kwargs);filename,format,overwrite) |
| 39 | +macro datax(args...) |
| 40 | + esc(datax_helper(args...)) |
38 | 41 | end |
39 | 42 |
|
40 | | -function datax(d::Dict{Symbol,<:Any};filename="data.tex",format::String="%.4g",overwrite=true) |
41 | | - filename = pop!(d,:filename,filename) |
42 | | - format = pop!(d,:format,format) |
43 | | - overwrite = pop!(d,:overwrite,overwrite) |
44 | | - permission = overwrite ? "w" : "a" |
45 | | - open(filename,permission) do f |
46 | | - println(f,"% Autogenerated by LaTeXDatax.jl, will be overwritten") |
47 | | - for (k,v) in d |
48 | | - print(f,"\\pgfkeyssetvalue{/datax/$k}{") |
49 | | - printdata(f,v,format) |
50 | | - print(f,"}\n") |
| 43 | +function datax_helper(args...) |
| 44 | + metaargs = Expr[] |
| 45 | + names = Symbol[] |
| 46 | + values = Any[] |
| 47 | + for a in args |
| 48 | + if a isa Symbol |
| 49 | + push!(names, a) |
| 50 | + push!(values, a) |
| 51 | + continue |
51 | 52 | end |
52 | | - end |
53 | | -end |
| 53 | + if a.head == :(=) |
| 54 | + push!(names, a.args[1]) |
| 55 | + push!(values, a.args[2]) |
| 56 | + continue |
54 | 57 |
|
55 | | -""" |
56 | | -```julia |
57 | | -@datax ... |
58 | | -``` |
59 | | -Print the arguments to a file readable by pgfkeys (Best for use with the |
60 | | -`datax` LaTeX package). Like the `datax()` function, but use the variables' |
61 | | -names. |
| 58 | + end |
| 59 | + if a.head == :(:=) |
| 60 | + push!(metaargs, Expr(:kw,a.args[1],a.args[2])) |
| 61 | + continue |
| 62 | + end |
| 63 | + error("I don't know what to do with argument $a") |
| 64 | + end |
62 | 65 |
|
63 | | -# Examples |
64 | | -```julia |
65 | | -a=2; |
66 | | -b=3.2u"m"; |
67 | | -c="hi"; |
68 | | -filename="datafile.tex"; |
69 | | -format="%.2g"; |
70 | | -@datax a b c filename format |
71 | | -``` |
72 | | -""" |
73 | | -macro datax(args...) |
74 | | - esc(datax_helper(args...)) |
75 | | -end |
76 | | -function datax_helper(args...) |
77 | | - names = Expr(:vect, QuoteNode.(args)...) |
78 | | - values = Expr(:vect, args...) |
| 66 | + names = Expr(:tuple, QuoteNode.(names)...) |
| 67 | + values = Expr(:tuple, values...) |
79 | 68 | quote |
80 | | - datax(Dict($names .=> $values)) |
| 69 | + LaTeXDatax.datax($names,$values;$(metaargs...)) |
| 70 | + nothing |
81 | 71 | end |
82 | 72 | end |
83 | 73 |
|
84 | | -printdata(f::IO,v::String,fmt::String) = print(f,v) |
85 | | -printdata(f::IO,v::Number,fmt::String) = print(f,"\\num{",sprintf1(fmt,v),"}") |
86 | | -printdata(f::IO,v::AbstractArray{<:Number},fmt::String) = print(f,"\\numlist{",prod(sprintf1.(fmt,v).*";"),"}") |
87 | | -printdata(f::IO,v::Tuple{<:Number,String},fmt::String) = print(f,"\\SI{",sprintf1(fmt,v[1]),"}{",v[2],"}") |
88 | | -printdata(f::IO,v::Tuple{AbstractArray{<:Number},String},fmt::String) = print(f, |
89 | | - "\\SIlist{", |
90 | | - prod( |
91 | | - sprintf1.(fmt,v[1]).*";") |
92 | | - ,"}{", |
93 | | - v[2], |
94 | | - "}" |
95 | | - ) |
96 | | -printdata(f::IO,v::Tuple{String,Vararg},fmt::String) = printdata(f,length(v)>2 ? v[2:end] : v[2], v[1]) |
97 | | - |
98 | | -function __init__() |
99 | | - @require Unitful="1986cc42-f94f-5a68-af5c-568840ba703d" begin |
100 | | - |
101 | | - function printdata(f::IO,v::Unitful.Quantity,fmt::String) |
102 | | - print(f,"\\SI{"*sprintf1(fmt,v.val)*"}{") |
103 | | - siunitxprint(f,Unitful.unit(v)) |
104 | | - print(f,"}") |
105 | | - end |
106 | | - function printdata(f::IO,v::AbstractArray{T},fmt::String) where T<:Unitful.Quantity |
107 | | - print(f,"\\SIlist{"*prod(sprintf1.(fmt,Unitful.ustrip(v)).*";")*"}{") |
108 | | - siunitxprint(f,Unitful.unit(T)) |
109 | | - print(f,"}") |
110 | | - end |
| 74 | +function datax(names, values; kwargs...) |
| 75 | + if haskey(kwargs, :io) |
| 76 | + datax(kwargs[:io], names, values; kwargs...) |
| 77 | + return nothing |
| 78 | + end |
| 79 | + if haskey(kwargs, :filename) |
| 80 | + datax(kwargs[:filename], names, values; kwargs...) |
| 81 | + return nothing |
| 82 | + end |
| 83 | + datax(stdout, names, values; kwargs...) |
| 84 | + return nothing |
| 85 | +end |
111 | 86 |
|
112 | | - function siunitxprint(f::IO,u::Unitful.FreeUnits) |
113 | | - prefixes = Dict( |
114 | | - -24 => "\\yocto", |
115 | | - -21 => "\\zepto", |
116 | | - -18 => "\\atto", |
117 | | - -15 => "\\femto", |
118 | | - -12 => "\\pico", |
119 | | - -9 => "\\nano", |
120 | | - -6 => "\\micro", |
121 | | - -3 => "\\milli", |
122 | | - -2 => "\\centi", |
123 | | - -1 => "\\deci", |
124 | | - 0 => "", |
125 | | - 1 => "\\deka", |
126 | | - 2 => "\\hecto", |
127 | | - 3 => "\\kilo", |
128 | | - 6 => "\\mega", |
129 | | - 9 => "\\giga", |
130 | | - 12 => "\\tera", |
131 | | - 15 => "\\peta", |
132 | | - 18 => "\\exa", |
133 | | - 21 => "\\zetta", |
134 | | - 24 => "\\yotta" |
135 | | - ) |
136 | | - for p in typeof(u).parameters[1] |
137 | | - p.power<0 && print(f,"\\per") |
138 | | - iszero(p.tens) || print(f,prefixes[p.tens]) |
139 | | - print(f,"\\$(lowercase(String(Unitful.name(p))))") |
140 | | - abs(p.power)==1 || print(f,"\\tothe$(Int64(abs(p.power)))") |
141 | | - end |
142 | | - end |
| 87 | +datax(io::IO, names, values; kwargs...) = printkeyval.(Ref(io),names,values; kwargs...) |
143 | 88 |
|
| 89 | +function datax(filename::String, names, values; permissions="w", kwargs...) |
| 90 | + if haskey(kwargs,:overwrite) |
| 91 | + if kwargs[:overwrite] |
| 92 | + permissions = "w" |
| 93 | + else |
| 94 | + permissions = "a" |
| 95 | + end |
144 | 96 | end |
| 97 | + open(filename, permissions) do io |
| 98 | + permissions == "w" && println(io, "% Autogenerated by LaTeXDatax.jl, will be overwritten") |
| 99 | + datax(io, names, values; kwargs...) |
| 100 | + end |
| 101 | +end |
| 102 | + |
| 103 | +function printkeyval(io::IO, name, value; kwargs...) |
| 104 | + print(io, "\\pgfkeyssetvalue{/datax/", name, "}{") |
| 105 | + printdata(io, value; kwargs...) |
| 106 | + print(io, "}\n") |
| 107 | + return nothing |
145 | 108 | end |
146 | 109 |
|
| 110 | +printdata(io::IO, v::String; kwargs...) = print(io, v) |
| 111 | +printdata(io::IO, v::Number; kwargs...) = print(io, latexify(v*u"one"; kwargs...)) |
| 112 | +printdata(io::IO, v; kwargs...) = print(io, latexify(v; kwargs...)) |
| 113 | + |
147 | 114 | end # module |
0 commit comments