Exporting Cairo Makie to tikz

I am trying to pycall svg2tikz so that I can build functions to plot CairoMakie to tikz, for seamless integration with LaTeX docs. I’ve edited the post title, as it’s specifically about CairoMakie output now.

The following code

using PyCall, CairoMakie

svg2tikz = pyimport("svg2tikz")
f = Figure()
ax = Axis(f[1,1])
scatter!(ax,rand(5),rand(5))
save("test.svg", f)
svg2tikz.convert_svg("test.svg")

produces

ERROR: PyError ($(Expr(:escape, :(ccall(#= C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:43 =# @pysym(:PyObject_Call), PyPtr, (PyPtr, PyPtr, PyPtr), o, pyargsptr, kw))))) <class 'ValueError'>
ValueError('Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration.')
  File "C:\Users\arn203\.julia\conda\3\lib\site-packages\svg2tikz\extensions\tikz_export.py", line 1453, in convert_svg       
    tikz_code = effect.convert(source.read(), **kwargs)
  File "C:\Users\arn203\.julia\conda\3\lib\site-packages\svg2tikz\extensions\tikz_export.py", line 1426, in convert
    self.parse(svg_file)
  File "C:\Users\arn203\.julia\conda\3\lib\site-packages\svg2tikz\extensions\tikz_export.py", line 721, in parse
    self.document = inkex.etree.parse(stream)
  File "src\lxml\etree.pyx", line 3521, in lxml.etree.parse
  File "src\lxml\parser.pxi", line 1876, in lxml.etree._parseDocument
  File "src\lxml\parser.pxi", line 1891, in lxml.etree._parseMemoryDocument

Stacktrace:
  [1] pyerr_check
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\exception.jl:62 [inlined]
  [2] pyerr_check
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\exception.jl:66 [inlined]
  [3] _handle_error(msg::String)
    @ PyCall C:\Users\arn203\.julia\packages\PyCall\BD546\src\exception.jl:83
  [4] macro expansion
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\exception.jl:97 [inlined]
  [5] #107
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:43 [inlined]
  [6] disable_sigint
    @ .\c.jl:458 [inlined]
  [7] __pycall!
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:42 [inlined]
  [8] _pycall!(ret::PyObject, o::PyObject, args::Tuple{String}, nargs::Int64, kw::Ptr{Nothing})
    @ PyCall C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:29
  [9] _pycall!
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:11 [inlined]
 [10] #_#114
    @ C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:86 [inlined]
 [11] (::PyObject)(args::String)
    @ PyCall C:\Users\arn203\.julia\packages\PyCall\BD546\src\pyfncall.jl:86
 [12] top-level scope
    @ REPL[10]:1

Just wondering if anyone could point me in the direction of what is going wrong here, so I can figure out a way to make it work, or abandon the idea as way-over-my-head.

Thanks in advance.

I’ve half cracked it. Just opened the svg file in notepad and deleted the encoding. Now to see if it actually produced the right picture…

Yep. It works. Could be a game changer for me.

1 Like

Only works for 2d plots as far as I can tell. And no text gets converted (e.g. axis ticks) unsurprisingly.

The generated tex file has a bunch of these essentially empty scopes

\begin{scope}[fill=black]
    \begin{scope}[shift={(19.08984,221.28125)}]
    \end{scope}
  \end{scope}

However, each one corresponds to the location of a single digit of an axis tick label. So working out which tick goes where and doing

\begin{scope}[fill=black]
    \begin{scope}[shift={(19.08984,221.28125)}]
    \node at (0,0) {5}; #e.g.
    \end{scope}
  \end{scope}

for each one will recover the axis tick labels, but now in LaTeX.
Would be great to automate this with a function that reads the locations of empty scopes and puts in the correct character. Or reads the original SVG file and decodes the characters.