rafaqz / FieldMetadata.jl

Metadata for julia fields
Other
22 stars 4 forks source link

Print to LaTeX table #2

Closed briochemc closed 5 years ago

briochemc commented 6 years ago

So you mentioned I could do this using FieldMetadata.jl (and Defaults.jl?) but I do not know if I did this the way you intended. Could you have a look at the example below and tell me what you think? Any comments welcome.

Currently this is my parameters:

@latexSymbol @describe @flattenable @printunits @units @default_kw struct Para{U}
    τu::U |  50.0 * spd | u"s"    | u"d"    | true  | "Specific uptake rate timescale"        | "\\tau_\\mathbf{u}"
    w₀::U |     1 / spd | u"m/s"  | u"m/d"  | true  | "Sinking velocity at surface"           | "w_0"
    w′::U |     1 / spd | u"s^-1" | u"d^-1" | false | "Vertical gradient of sinking velocity" | "w'"
    κ::U  |  0.25 / spd | u"s^-1" | u"d^-1" | false | "Remineralization rate"                 | "\\kappa"
    τg::U | 365e6 * spd | u"s"    | u"yr"   | false | "Geological Restoring"                  | "\\tau_\\mathrm{geo}"
end

where I have needed to create a few "tags" and a unit for years:

@metadata printunits nothing
@metadata describe ""
@metadata latexSymbol ""
# Define the year unit (not in Unitful)
@unit(yr, "yr", Year, 365.0u"d", true)
Unitful.register(@__MODULE__)

My solution to printing a LaTeX table works like this:

julia> print_LaTeX_table(p₀)
Latex table for the parameters:
\begin{table*}[t]
    \centering
    \begin{tabular}{lllll}
        Parameter & Description & Value & Unit & Optimized? \\ \hline
        $\tau_\mathbf{u}$ & Specific uptake rate timescale & $50$ & d & yes\\
        $w_0$ & Sinking velocity at surface & $1$ & m\,d$^{-1}$ & yes\\
        $w'$ & Vertical gradient of sinking velocity & $1$ & d$^{-1}$ & no\\
        $\kappa$ & Remineralization rate & $0.25$ & d$^{-1}$ & no\\
        $\tau_\mathrm{geo}$ & Geological Restoring & $1 \times 10^{6}$ & yr & no\\
        \label{T:Parameters}
    \end{tabular}
    \caption{
    }
\end{table*}

where the print_LaTeX_table function is defined by

function print_LaTeX_table(p::Para)
    println("Latex table for the parameters:")
    println("\\begin{table*}[t]")
    println("    \\centering")
    println("    \\begin{tabular}{lllll}")
    println("        Parameter & Description & Value & Unit & Optimized? \\\\ \\hline")
    for f in fieldnames(typeof(p))
        LaTeX_line = "        " # Indent
        LaTeX_line = LaTeX_line * "\$" * latexSymbol(p, f) * "\$" # Parameter Symbol
        LaTeX_line = LaTeX_line * " & " * describe(p, f) # Parameter Description
        val = uconvert(printunits(p, f), getfield(p, f) * units(p, f)) # Value in print units
        LaTeX_line = LaTeX_line * " & \$" * latexify(ustrip(val)) * "\$"
        LaTeX_line = LaTeX_line * " & " * latexify(printunits(p, f)) # print units
        LaTeX_line = LaTeX_line * " & " * latexify(flattenable(p, f)) * "\\\\"
        println(LaTeX_line)
    end
    println("        \\label{T:Parameters}")
    println("    \\end{tabular}")
    println("    \\caption{")
    println("    }")
    println("\\end{table*}")
end

which uses my latexify function:

function latexify(U::Unitful.Units)
    str = string(U)
    str = replace(str, r"\^-(?<exp>\d+)" => s"$^{-\g<exp>}$") # add brackets around exponents
    str = replace(str, r"dy" => s"d") # Replace "dy" with "d" for days
    str = replace(str, r"\s" => s"\\,") # replace spaces with small spaces
    return str
end

latexify(optimized::Bool) = optimized ? "yes" : "no"

function latexify(val::R) where R<:Real
    str = @sprintf("%.2g", val)
    str = replace(str, r"e\+0+(?<exp>\d+)" => s" \\times 10^{\g<exp>}")
    str = replace(str, r"e\-0+(?<exp>\d+)" => s" \\times 10^{-\g<exp>}")
    return str
end
rafaqz commented 6 years ago

Thats too much code for me to read :)

Isn't there a package that does latex tables??

I would concentrate on getting metadata into a dataframe then use some tool made for that. And keep the whole process generalised.

FieldMetadata is just a generic way of attaching metadata to arbitrary structures. Flatten converts arbitrary structures to generic flat structures like vectors. Vectors are easily converted to the generic tabular data like dataframes. Then insert a general way of creating your latex table from a dataframe.

I imagine it should only be 10 lines of code total, not including the metadata on the structs.

briochemc commented 6 years ago

I think I understand what you are saying, but

I would concentrate on getting metadata into a dataframe

is precisely what I do not know how to do, so I went with putting everything in the LaTeX table directly...

rafaqz commented 6 years ago

So easy!

My announcment post is an example of doing exactly that: https://discourse.julialang.org/t/ann-metafields-jl-and-flatten-jl-packages-for-writing-composable-models/12849

But the syntax has probably changed a little.