korsbo / latexify.jl Goto Github PK
View Code? Open in Web Editor NEWConvert julia objects to LaTeX equations, arrays or other environments.
License: MIT License
Convert julia objects to LaTeX equations, arrays or other environments.
License: MIT License
Hi!
d = DataFrame(A = 1:4, B = ["A's blues", "B", "C", "D"],
C = ["x/y", "x_subscript", "gamma(x)", 1//2])
4×3 DataFrames.DataFrame
│ Row │ A │ B │ C │
├─────┼───┼───────────┼─────────────┤
│ 1 │ 1 │ A's blues │ x/y │
│ 2 │ 2 │ B │ x_subscript │
│ 3 │ 3 │ C │ gamma(x) │
│ 4 │ 4 │ D │ 1//2 │
but
md(d)
ParseError("extra token \"blues\" after end of expression")
#parse#234(::Bool, ::Bool, ::Function, ::String, ::Int64) at parse.jl:222
(::Base.#kw##parse)(::Array{Any,1}, ::Base.#parse, ::String, ::Int64) at <missing>:0
#parse#235(::Bool, ::Function, ::String) at parse.jl:232
latexinline(::String) at latexinline.jl:2
collect_to!(::Array{LaTeXStrings.LaTeXString,2}, ::Base.Generator{Array{Any,2},Latexify.#latexinline}, ::Int64, ::Int64) at array.jl:508
collect(::Base.Generator{Array{Any,2},Latexify.#latexinline}) at array.jl:476
#mdtable#151(::Bool, ::Array{Symbol,1}, ::Array{Any,1}, ::Bool, ::Function, ::Array{Any,2}) at mdtable.jl:60
(::Latexify.#kw##mdtable)(::Array{Any,1}, ::Latexify.#mdtable, ::Array{Any,2}) at <missing>:0
#mdtable#168(::Array{Any,1}, ::Function, ::DataFrames.DataFrame) at mdtable.jl:85
mdtable(::DataFrames.DataFrame) at mdtable.jl:85
#md#120(::Symbol, ::Array{Any,1}, ::Function, ::DataFrames.DataFrame, ::Vararg{DataFrames.DataFrame,N} where N) at md.jl:6
md(::DataFrames.DataFrame, ::Vararg{DataFrames.DataFrame,N} where N) at md.jl:4
include_string(::String, ::String) at loading.jl:522
eval(::Module, ::Any) at boot.jl:235
(::Atom.##119#122)() at eval.jl:148
withpath(::Atom.##119#122, ::Void) at utils.jl:30
withpath(::Function, ::Void) at eval.jl:38
macro expansion at eval.jl:147 [inlined]
(::Atom.##118#121{Dict{String,Any}})() at task.jl:80
julia> latexify( ( 2.5, 4.0 ) )
ERROR: MethodError: no method matching latexraw(::Tuple{Float64,Float64})
This would be very helpful, many thanks.
I'm having an issue with using Latexify with chemical reactions.
For example:
`using DiffEqBiological, Latexify
rs = @reaction_network begin
hillr(P₃,α,K,n), ∅ --> m₁
hillr(P₁,α,K,n), ∅ --> m₂
hillr(P₂,α,K,n), ∅ --> m₃
(δ,γ), m₁ ↔ ∅
(δ,γ), m₂ ↔ ∅
(δ,γ), m₃ ↔ ∅
β, m₁ --> m₁ + P₁
β, m₂ --> m₂ + P₂
β, m₃ --> m₃ + P₃
μ, P₁ --> ∅
μ, P₂ --> ∅
μ, P₃ --> ∅
end α K n δ γ β μ;
latexify(rs)
latexify(rs,env=:chemical)'
The error I get is
ERROR: MethodError: no method matching chemical_arrows(::Tuple{Array{LaTeXString,1},Array{Union{Float64, Int64, Expr, Symbol},1}}; noise_var=:W, env=:chemical, bracket=false, noise=false, noise_only=false)
Closest candidates are:
chemical_arrows(::DiffEqBase.AbstractReactionNetwork; expand, double_linebreak, mathjax, starred, kwargs...) at
Using Julia 1.1 with latest release of Latexify...
Markdown uses underscores to denote formatting in italics. This can sometimes cause problems with latexify using the latex=false
kwarg.
latexify([:x_y_z; :a_b_c], env=:mdtable, latex=false)
xyz |
---|
abc |
preferred behaviour:
x_y_z |
---|
a_b_c |
Fix:
Add a new kwarg which toggles these behaviours, use the latter one as a default.
From
B=[1 0 5; 2 5 4]
C=[2;3;1]
latexify(B*C)|>print
I get
\begin{equation}
\left[
\begin{array}{cc}
7 & 23 \\
\end{array}
\right]
\end{equation}
but I think it should be
\begin{equation}
\left[
\begin{array}{cc}
7 \\ 23
\end{array}
\right]
\end{equation}
p.s. great package, thanks!
Something has changed in the DataFrames API and a test is now raising an error.
I would like to use latexify with PyPlot. The following code works for me
rcParams = PyDict(matplotlib["rcParams"]) rcParams["text.usetex"] = true; rcParams["text.latex.preamble"] = raw"\usepackage{{amsmath}}"; ax.text(-0.75,-0.75,L"$\left[\begin{array}{cc}0.0 & -0.2 \\0.0 & -0.2 \\\end{array} \right]$");=
but I would like to use latexify instead in
A = [0,-0.2; 0, +0.2]; ax.text(-0.75,-0.75,latexify(A))
instead. But I only manage to get
A_new = replace(replace(replace(latexify(A), "\\begin{equation}" => L"$"), "\\end{equation}" => L"$"), "\n" => "") ax.text(-0.25,-0.75,A_new)
to work while for latexify(A; env=:inline)
, I get
LaTeXString[L"$0.0$" L"$-0.2$"; L"$0.2$" L"$0.0$"]
which cannot be used by text. If you had an env to directly return the right format ... that would be very cool. Thanks for considering...
The tables of possible arguments are broken for the latest docs. Fix before release.
using Latexify
ex = :(exp.(z)
)
latexify(ex)
Gives
Latexify.jl's latexoperation does not know what to do with one of the
operators in your expression (z).
Of course, this works great with :(exp(z))
. My suggestion: Latexify just strips out all broadcasting in a pre-step?
I am having a slight issue trying to constrain the output of some huge reaction network.
I define some reaction_functions in DiffEqBiological but when I use
latexify(rn; expand=false)
it displays everything expanded...
I guess this expand false feature is only for predefined Hill functions, is it possible to expand it to generic @reaction_func's?
Automatic testing of latexify is currently a little painful since it relies on precise equality between the string generated by a function call and a string typed out in the test script. Generating such tests is pretty easy using the Latexify.@generate_test
macro, but this exact string matching gives no leeway for making otherwise inconsequential changes to how latexify
formats its output.
Is there a way of testing that latexify
gives the desired result without being completely inflexible when it comes to making small changes?
This is related to the question of what should be considered part of the API, #77.
Hi there,
I thought I'd give Latexify a try after watching the JuliaCon2018 video (great talk!), but it failed to compile. Is is just a version 1.0 thing or am I missing something? See stacktrace below (some parts hidden)
Please let us know,
Cheers,
Benoit.
julia> using Latexify
[ Info: Precompiling Latexify [23fbe1c1-3f47-55db-b15f-69d7ec21a316]
ERROR: LoadError: UndefVarError: Markdown not defined
Stacktrace:
[1] include at ./boot.jl:317 [inlined]
[2] include_relative(::Module, ::String) at ./loading.jl:1038
[3] include(::Module, ::String) at ./sysimg.jl:29
[4] top-level scope at none:2
[5] eval at ./boot.jl:319 [inlined]
[6] eval(::Expr) at ./client.jl:389
[7] top-level scope at ./none:3
in expression starting at /Users/██████/.julia/packages/Latexify/fv4O8/src/Latexify.jl:5
ERROR: Failed to precompile Latexify [23fbe1c1-3f47-55db-b15f-69d7ec21a316] to /Users/██████/.julia/compiled/v1.0/Latexify/AItXo.ji.
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] macro expansion at ./logging.jl:313 [inlined]
[3] compilecache(::Base.PkgId, ::String) at ./loading.jl:1184
[4] _require(::Base.PkgId) at ./logging.jl:311
[5] require(::Base.PkgId) at ./loading.jl:852
[6] macro expansion at ./logging.jl:311 [inlined]
[7] require(::Module, ::Symbol) at ./loading.jl:834
Holding onto the SymEngine variables makes ParameterizedFunctions not compatible with precompilation so I plan on getting rid of them in the Julia v0.7 version. However, I wanted to make sure Latexify.jl could still work well. funcs
is a Vector{Expr}
so I am curious why you use the Matrix{SymEngine.Basic}
instead of the Matrix{Expr}
Jex
for the Jacobian expression. If there's anything you need to ensure it's saved well we can make that change and drop the symjac
field safely. Thanks for your work here!
It would make sense to have a method of latextabular
(#1) which takes a DataFrame as input.
Is there a way to convert unicode to the corresponding LaTeX command? E.g., latexify(α)
to actually print $\alpha$
instead of $α$
? (Or something similar to this idea?)
Latexify recipes are currently not recursive. This needs to be fixed!
This should work:
using Latexify
struct MyFloat
x::Float64
end
@latexrecipe function f(mf::MyFloat)
fmt --> "%.4e"
return mf.x
end
struct MyFloatWrapper
x::MyFloat
end
@latexrecipe function f(w::MyFloatWrapper)
return w.x
end
latexify(MyFloatWrapper(MyFloat(3.3894792)))
Any chance of getting an updated release that includes the cdot
keyword? (I'd like to use this in a class. Thanks!
The tests fail due to some inconsistent handling of whitespaces at the end of some lines.
The source code for support of external packages has been organised into a plugins
folder. The tests for these functions should be re-organised accordingly.
The documentation is messed up since the code evaluation of Documenter.jl seems to have failed.
While expressions containing arrays are generally formatted correctly by Latexify, statements such as x=[1 0]
either fail to properly format the array contents, or (in the case of array literals) result in errors.
julia> latexify(zeros(2))
L"\begin{equation}
\left[
\begin{array}{c}
0.0 \\
0.0 \\
\end{array}
\right]
\end{equation}
"
julia> latexify(:(x=$(zeros(2))))
L"$x = [0.0, 0.0]$"
Expected output: the same LaTeX as in the latexify(zeros(2))
call, but prepended with "x =".
More complex arrays can lead to illegible output:
julia> arr=[0 -im; im 0]
2×2 Array{Complex{Int64},2}:
0+0im 0-1im
0+1im 0+0im
julia> latexify(:(x=$(arr)))
L"$x = Complex{Int64}[0 + 0im 0 - 1im; 0 + 1im 0 + 0im]$"
Using array literals as an input to latexify results in errors for both statements and expressions. This is more of an issue for statements where literals are more likely to be convenient (e.g. in the case above where I had to explicitly assign arr
first in order to avoid using a literal):
julia> latexify([0 1])
L"\begin{equation}
\left[
\begin{array}{cc}
0 & 1 \\
\end{array}
\right]
\end{equation}
"
julia> latexify(:[0 1])
ERROR: Latexify.jl's latexoperation does not know what to do with one of the
operators in your expression (0).
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] #latexoperation#19(::Bool, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(Latexify.latexoperation), ::Expr, ::Array{Symbol,1
}) at /home/david/.julia/packages/Latexify/0gnwF/src/latexoperation.jl:127
[3] latexoperation at /home/david/.julia/packages/Latexify/0gnwF/src/latexoperation.jl:10 [inlined]
[4] (::getfield(Latexify, Symbol("#recurseexp!#4")){Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}})(::Expr) at /home/david/.julia/packages/
Latexify/0gnwF/src/latexraw.jl:71
[5] #latexraw#3(::Bool, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(latexraw), ::Expr) at /home/david/.julia/packages/Latexif
y/0gnwF/src/latexraw.jl:74
[6] latexraw at /home/david/.julia/packages/Latexify/0gnwF/src/latexraw.jl:62 [inlined]
[7] #latexinline#42 at /home/david/.julia/packages/Latexify/0gnwF/src/latexinline.jl:2 [inlined]
[8] latexinline(::Expr) at /home/david/.julia/packages/Latexify/0gnwF/src/latexinline.jl:2
[9] #latexify#25(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(latexify), ::Expr) at /home/david/.julia/packages/Latexify/0gnwF
/src/latexify_function.jl:11
[10] latexify(::Expr) at /home/david/.julia/packages/Latexify/0gnwF/src/latexify_function.jl:4
[11] top-level scope at REPL[42]:1
julia> latexify(:(x=[0 1]))
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Symbol
Closest candidates are:
convert(::Type{T}, ::T) where T at essentials.jl:167
Symbol(::Any...) at strings/basic.jl:206
Stacktrace:
[1] setindex!(::Array{Symbol,1}, ::Int64, ::Int64) at ./array.jl:766
[2] (::getfield(Latexify, Symbol("#recurseexp!#4")){Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}})(::Expr) at /home/david/.julia/packages/
Latexify/0gnwF/src/latexraw.jl:67
[3] #latexraw#3(::Bool, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(latexraw), ::Expr) at /home/david/.julia/packages/Latexif
y/0gnwF/src/latexraw.jl:74
[4] latexraw at /home/david/.julia/packages/Latexify/0gnwF/src/latexraw.jl:62 [inlined]
[5] #latexinline#42 at /home/david/.julia/packages/Latexify/0gnwF/src/latexinline.jl:2 [inlined]
[6] latexinline(::Expr) at /home/david/.julia/packages/Latexify/0gnwF/src/latexinline.jl:2
[7] #latexify#25(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(latexify), ::Expr) at /home/david/.julia/packages/Latexify/0gnwF
/src/latexify_function.jl:11
[8] latexify(::Expr) at /home/david/.julia/packages/Latexify/0gnwF/src/latexify_function.jl:4
[9] top-level scope at REPL[43]:1
Generally you can get something that displays fine by simply appending the statement portion of the LaTeX explicitly using LaTeXStrings (being careful to avoid literals), but the output is technically wrong since the statement portion lies outside of the equation block.
julia> arr=[0 -im; im 0]
2×2 Array{Complex{Int64},2}:
0+0im 0-1im
0+1im 0+0im
julia> latexstring("x="*latexify(arr).s)
L"$x=\begin{equation}
\left[
\begin{array}{cc}
0+0\textit{i} & 0-1\textit{i} \\
0+1\textit{i} & 0+0\textit{i} \\
\end{array}
\right]
\end{equation}
$"
julia> dump(:(x=$(zeros(2))))
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol x
2: Array{Float64}((2,)) [0.0, 0.0]
julia> dump(:(x=[0, 2]))
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol x
2: Expr
head: Symbol vect
args: Array{Any}((2,))
1: Int64 0
2: Int64 2
julia> dump(:(x=[0 2]))
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol x
2: Expr
head: Symbol hcat
args: Array{Any}((2,))
1: Int64 0
2: Int64 2
julia> dump(:(x=[0;2]))
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol x
2: Expr
head: Symbol vcat
args: Array{Any}((2,))
1: Int64 0
2: Int64 2
This received an upper bound in METADATA when DiffEqBase.jl updated its syntax. I'm not sure if it's actually needed, and it would be best to re-tag after the tests have been updated. That will naturally get rid of the upper bound.
Some printf formats are very slow, especially when rendering a table with many numbers for example.
julia> @time latexify(rand(10,10), fmt="%.4g");
6.614370 seconds (13.24 M allocations: 689.851 MiB, 1.66% gc time)
I think this is because of the code in numberformatters.jl
:
s = @eval @sprintf $(f.fmt) $x
The issue is that the eval is called for each number $x. But the format is the same every time so this is unnecessary. If we generate the formatter in advance, things are much better.
julia> fmt="%.4g"
"%.4g"
julia> f = @eval x -> @sprintf($fmt, x);
julia> @time latexify(rand(10,10), fmt=f);
0.225207 seconds (378.32 k allocations: 19.770 MiB)
If we use f again, it will be even faster as f is compiled(?) the first the it is called.
It would be nice if this could be implemented somehow and so that the above workaround is not needed. I'm not sure how it should be done, hence I've made this issue instead of a PR.
Discourse links
It seems that if a variable contains both unicode and ascii character, latexify will product incorrect output:
julia> latexify("δa")
L"$\deltaa$"
but what I want is :$\delta a$,
adding _
would not help because it will change into \delta_{a}
。
I am not sure whether this is intended. But since it's impossible to use spaces in variable names, so I can't get around it.
This has never been an issue for me since formatting is easily added after copying latex code to a document but that approach is not automated and does not work with for example Weave.jl. It would, therefore, be nice to have better customizability of final table formatting.
Currently, the latexify recursively translates expressions and flattens out the expression tree in the process. An alternative would be to keep the tree structure of the Expression until it is time to display the equation. Each kind of term (division, addition, ...) could be represented by a type which has an overload to a convert
function.
This could allow for a mapping between the original expression and the latexified output. It could then be possible to allow for backwards propagation of changes (change the latex formula and have it reflected in the original expression). Also, and maybe more realistically, keeping an abstract representation could alleviate issues of automated testing which currently breaks for any minor change in latexify's output format.
This concept is still far from developed enough for me to actually start implementing.
The usefulness of latexify might increase if we make it easier for external packages to generate latexify support for their objects. While this is possible by overloading functions, it is neither documented nor very stable to internal latexify changes. Instead, we could provide a DSL to create "recipes" like those of RecipesBase.jl. That way, we could have an API which is independent on latexify's internals.
This could make it quick and easy for anyone to ensure that their types can be latexified. It would also remove myself as a bottleneck.
Im trying to latexify an array of strings, which Latexify complains about since they can not be parsed as latex math. The suggestion to add kwarg latex=false
fails as well, saying that latex
is not a supported keyword argument
julia> topics
20×6 Array{String,2}:
"time" "controller" "model" "robot" "glucose" "linear"
"paper" "process" "combustion" "force" "insulin" "time"
"based" "pid" "engine" "model" "models" "model"
"applications" "design" "paper" "based" "students" "optimal"
"model" "paper" "cylinder" "using" "blood" "paper"
"software" "based" "pressure" "industrial" "data" "feedback"
"real" "performance" "controller" "estimation" "learning" "stability"
"performance" "controllers" "ignition" "paper" "course" "method"
"resource" "tuning" "operating" "method" "based" "optimization"
"design" "method" "based" "motion" "paper" "based"
"optimization" "proposed" "cycle" "robots" "innovation" "using"
"application" "loop" "temperature" "sensor" "prediction" "function"
"scheduling" "processes" "fuel" "position" "gt" "algorithm"
"modelica" "model" "production" "approach" "predictors" "design"
"implementation" "time" "injection" "results" "lt" "proposed"
"cloud" "disturbance" "using" "proposed" "patient" "approach"
"dynamic" "using" "low" "time" "technology" "constraints"
"resources" "robustness" "power" "vehicle" "time" "loop"
"simulation" "closed" "hcci" "sensors" "using" "network"
"approach" "methods" "models" "models" "development" "distributed"
julia> latexify(topics)
ERROR: Error in Latexify.jl: You are trying to create latex-maths from a string that cannot be parsed as an expression. If you are trying to make a table or an array with plain text, try passing the keyword argument `latex=false`.
Stacktrace:
[1] latexraw(::String) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexraw.jl:94
[2] iterate at ./generator.jl:47 [inlined]
[3] collect_to!(::Array{String,2}, ::Base.Generator{Array{String,2},typeof(latexraw)}, ::Int64, ::Int64) at ./array.jl:656
[4] collect_to_with_first!(::Array{String,2}, ::String, ::Base.Generator{Array{String,2},typeof(latexraw)}, ::Int64) at ./array.jl:643
[5] collect(::Base.Generator{Array{String,2},typeof(latexraw)}) at ./array.jl:624
[6] latexraw at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexraw.jl:78 [inlined]
[7] #latexarray#3(::Symbol, ::Bool, ::Bool, ::Bool, ::Function, ::Array{String,2}) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexarray.jl:25
[8] latexarray(::Array{String,2}) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexarray.jl:17
[9] #latexify#2(::Symbol, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::Array{String,2}) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexify_function.jl:4
[10] latexify(::Array{String,2}) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexify_function.jl:2
[11] top-level scope at none:0
julia> latexify(topics, latex=false)
ERROR: MethodError: no method matching latexarray(::Array{String,2}; latex=false)
Closest candidates are:
latexarray(::AbstractArray{T,2} where T; adjustment, transpose, double_linebreak, starred) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexarray.jl:17 got unsupported keyword argument "latex"
latexarray(::AbstractArray...; kwargs...) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexarray.jl:41
latexarray(::AbstractArray{T,1} where T; kwargs...) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexarray.jl:40
...
Stacktrace:
[1] kwerr(::NamedTuple{(:latex,),Tuple{Bool}}, ::Function, ::Array{String,2}) at ./error.jl:97
[2] (::getfield(Latexify, Symbol("#kw##latexarray")))(::NamedTuple{(:latex,),Tuple{Bool}}, ::typeof(latexarray), ::Array{String,2}) at ./none:0
[3] #latexify#2(::Symbol, ::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:latex,),Tuple{Bool}}}, ::Function, ::Array{String,2}) at /local/home/fredrikb/.julia/packages/Latexify/3shva/src/latexify_function.jl:4
[4] (::getfield(Latexify, Symbol("#kw##latexify")))(::NamedTuple{(:latex,),Tuple{Bool}}, ::typeof(latexify), ::Array{String,2}) at ./none:0
[5] top-level scope at none:0
ex = :(-1 -(-1-1))
latexify(ex)
This is just plain wrong and needs to be fixed.
The last few releases are not visible in the docs. Probably some change to Documenter.jl.
Currently Latexify.jl presents one function for each kind of output (inline, array, align, etc), as well as one function (latexify
) which tries to infer the preferred output. An alternative to this would be to just have one function to which you can pass a kwarg to specify what latex environment you want to output.
For example, latexalign(x)
could be replaced by latexify(x; env=:align)
. latexify
could still use clever defaults which depends on the input type, but allow the user to override this.
The difference would be rather minimal, but I'm wondering if this would be more natural/easier to remember.
Any input would be appreciated.
How hard would it be to take latex and output some crude julia code?
In Julia, one can inspect the expressions that build up a method with @code_lowered
. The returned object does have all the information required to deduce what the method does. I have been playing around with latexifying simple julia functions. The code for this can be found in the function_support
branch.
I have implemented rudimentary support for latexifying some simple functions:
using Latexify
gamma_pdf(t, n, r) = r^n*t^(n-1)*exp(-r*t)/gamma(n)
latexify(gamma_pdf, (1,1,1))
(I need to pass a tuple or array of arguments to my gamma_pdf
so that Julia can figure out which method to use)
A multi-line example:
function ode(du, u, p, t)
du[1] = p[1] * u[2]
du[2] = - u[1]
end
latexify(ode, (1,1,1,1))
\begin{equation}
\begin{array}{l}
\textrm{du}\left[1\right] = p\left[1\right] \cdot u\left[2\right] \\
\textrm{du}\left[2\right] = - u\left[1\right] \\
\end{array}
\end{equation}
However, this is a bit of a house of cards in two repects: One is that the code is hard to read/understand, which makes the package harder to maintain. The other respect is that It breaks for any operation that is not explicitly defined in latexoperation
.
For example:
f(n) = [i for i in 1:n]
latexify(f, (1))
will error.
Support for very simple stuff is achievable. Support for truly general functions should be theoretically possible, but I can't see it being feasible.
Does anyone have feedback on this/is anyone willing and able to implement a better version than I have done myself?
Also, is this worth working further on at all? It has already been a bit of a time-sink.
Perhaps this would be a neat example for the documentation.
rn = @reaction_network gnrdtype begin
c1, G --> G + M
c2, M --> M + P
c3, M --> 0
c4, P --> 0
c5, 2P --> P2
c6, P2 --> 2P
c7, P2 + G --> P2G
c8, P2G --> P2 + G
end c1 c2 c3 c4 c5 c6 c7 c8
print(latexify(rn, env=:chemical, mathjax=false))
gives
\begin{align}
\ce{ G &->[c1] G + M}\\
\ce{ M &->[c2] M + P}\\
\ce{ M &->[c3] \varnothing}\\
\ce{ P &->[c4] \varnothing}\\
\ce{ 2 \cdot P &<=>[{c5}][{c6}] P2}\\
\ce{ P2 + G &<=>[{c7}][{c8}] P2G}\\
\end{align}
which when rendered into Latex has subscripts for c1 to c4 but not c5 to c8:
Dropping the {} about c5 to c8 restores the subscripts.
Right now, for SDEs Latexify seems to output the coefficient of the noise term, but with an equation that it is equal to the time-derivative of the original variable. That is, for the reaction A-->0 the ODE is
dA/dt = -k*A
The SDE is
dA = -k*A*dt - \sqrt(k*A)*dW(t)
for a Brownian Motion, W(t). Latexify outputs for the "noise"
dA/dt = - \sqrt(k*A)
which seems a bit confusing to me. Would it be possible to add an option to output the full SDE? (I guess each equation would just get an independent dW_i(t)?)
We should have functions for generating markdown-formatted versions of all the latexXXX
functions.
\
\
Shorthands such as latexalign
, mdtable
, etc., which can be accessed via latexify(x; env=:align)
, ect., will be removed from the public API and should not be exported. Removing them allows for a simpler API and for internal updates without major releases.
This will be breaking and I can't think of a good way of signalling this deprecation to users without having to rename the functions internally (which I don't want to do). If I can't think of anything better, there will therefore be a silent removal of the exports at the release of 1.0.
One often uses the same set of kwargs for an entire session. It would make sense to be able to change the default kwarg value with a single call.
:kwarg => default_value
.The function name latexify
is a bit special since it shares name with the package itself. It is memorable and one of the shortest versions of latex<insert ending>
possible.
Currently, the latexify
function is used for creating latex inline equations, $some equation$
. If you pass it some AbstractArray, latexify
will recursively convert its elements. But, while this is a nice feature I do not find myself using it very much. I thus wonder whether we are not wasting the package's prime function name on something which we instead could call latexinline
.
Instead, we could use the name latexify
for a function which tries to infer what kind of LaTeX environment is suitable for the given input. We could for example let
latexify(x::AbstractArray) = latexarray(x)
latexify(ode::AbstractParameterizedFunction) = latexalign(ode)
latexify(x::Expr) = latexinline(x) # Same behaviour as before
This way, we could have a "one-size-fits-all" function for most user cases. We could also allow for keyword arguments in some ambiguous cases, example:
function latexify(x::AbstractArray; env=:array)
env == :array && return latexarray(x)
env == :table && return latextable(x)
end
The downside would be that the user would not really know what they will get when they use latexify(some input)
. And, while some input types have an obvious preferred output, others do not. Example: should latexify(::Matrix)
generate an array or a table by default?
How are you using Latexify.jl, and what design would feel more natural to you?
Before the release of 1.0, there must be a clear demarcation of what is or is not part of the API. This is especially needed for other packages which have latexify as a dependency and which use the @latexrecipe
macro. SemVer is useless if nothing is considered part of the API and it is crippling if the API includes everything.
Clearly part of the API:
latexify
latexify
for all different kinds of input types or combinations thereof.latexify
. env=:align
gives a latex align environment, ect. The general form of the output string.Less clear:
A few spaces here or there or whether something is surrounded by \mathrm{}
should not matter too much for users. Having this exact string be a part of the API means that every little enhancement to the output would be a breaking change and requires a major version bump. This would slow down such enhancements greatly. However, not having in the API makes testing very difficult which is a problem for anyone relying on a @latexrecipe
.
Although the mathematics generated by DiffEqBiologcals @reaction_network
has not changed, the structure of the expression tree has. This causes test errors.
We really should be testing each and every feature of Latexify and currently we are not.
Test generation is made easy by a macro that we supply:
using Latexify
@Latexify.generate_test latexify("x/y")
generates a test and puts it in your clipboard to be pasted:
@test latexify("x/y") ==
raw"$\frac{x}{y}$"
One just have to make sure that the test does actually do what was expected. For markdown, one must also replace the raw
with Markdown.MD
and get the first newline right.
By using clipboard
, we can send a LaTeX command to clipboard. So we can omit the process of printing a LaTeX command and copying it.
For example,
return LaTeXString(str)
↓
latexstr = LaTeXString(str)
clipboard(latexstr)
return latexstr
Would you implement above feature?
This is a fantastic package thanks to which I'm able to export data from Julia onto my .tex document as a table. I'm having some minor issues with this feature. I'd want to convert the ugly numbers (12434354.23234
) into a scientific format (1.24e+7
) which is usually preferred for tables in LaTeX. Is it possible to do this at the moment?
In Jupyter notebooks and such I would like to have Latexify be the output by default. Is there a nice way to do that? It would be nice to have the solution documented.
It seems that currently Latexify.jl doesn't handle trigonometric function well:
julia> latexify(:(sin(x)^2))
L"$\sin\left( x \right)^{2}$"
But I think a more appropriate output would be$\sin^{2}\left( x \right)$
(that is ^{2} should place on sin
instead on (x)
)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.