leo-colisson / robust-externalize

A LaTeX library to cache pictures (including tikz, python code, and more) in a robust, customizable, and pure way.
7 stars 2 forks source link

Can not use resizebox around python cacheMeCode #24

Closed dflvunoooooo closed 4 months ago

dflvunoooooo commented 4 months ago

I somehow can not use a resizebox around a python preset. I get the error You can't usemacro parameter character #' in math mode`.

\documentclass{scrartcl} 

\usepackage{robust-externalize}

\begin{document}
\begin{figure}
    \centering
    \resizebox{\textwidth}{!}{
    \begin{CacheMeCode}{python}
        import matplotlib.pyplot as plt
        import matplotlib
        matplotlib.use('pgf')
        year = [2014, 2015, 2016, 2017, 2018, 2019]
        tutorial_count = [39, 117, 111, 110, 67, 29]
        plt.plot(year, tutorial_count, color="#6c3376", linewidth=2)
        plt.title("Simple plot")
        plt.xlabel('Year')
        plt.ylabel('Number of futurestud.io Tutorials')
        print(get_filename_from_extension(".pgf"))
        plt.savefig("__ROBEXT_OUTPUT_PDF__")
    \end{CacheMeCode}
    }
    \caption{test}%
    \label{py:test}
\end{figure}

\end{document}
tobiasBora commented 4 months ago

This is because LaTeX will interpret code differently when inside a macro or some environments (like align). So here, it thinks that #6c3376 refers to the 6-th argument of the macro… which of course makes no sense. The only solution is to define a temporary placeholder before, like:

\documentclass{scrartcl} 

\usepackage{robust-externalize}

\begin{document}
\begin{figure}
  \centering
  \begin{PlaceholderFromCode}{__TMP__}
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('pgf')
year = [2014, 2015, 2016, 2017, 2018, 2019]
tutorial_count = [39, 117, 111, 110, 67, 29]
plt.plot(year, tutorial_count, color="#6c3376", linewidth=2)
plt.title("Simple plot")
plt.xlabel('Year')
plt.ylabel('Number of futurestud.io Tutorials')
print(get_filename_from_extension(".pgf"))
plt.savefig("__ROBEXT_OUTPUT_PDF__")   
  \end{PlaceholderFromCode}
  \resizebox{\textwidth}{!}{
    \cacheMe[python]{__TMP__}
  }
  \caption{test}%
  \label{py:test}
\end{figure}

\end{document}

Note also a few remarks:

  1. DO NOT indent python code to align with \begin{*Code}: this library copies verbatim ALL character in this environment, including the spaces at the beginning of the line… since python relies on indentation, it will not do what you expect… I was even surprised to see you don't get any error; in fact it only works by pure chance: here you code is inserted in the content of another function in the python preset (finished_with_no_error), and it turns out that finished_with_no_error is run automatically at the end, running also your code… but it is definitely not something intended, I should rather output an error in that case. I will try to find a better solution for this issue, I created https://github.com/leo-colisson/robust-externalize/issues/25 to deal with that.
  2. If you use the .pdf output, matplotlib will actually generate a pdf file, and ignore the fact that you use the pgf render engine. So here it will not \input a pgf file, it will \includegraphics the pgf file. See https://github.com/leo-colisson/robust-externalize/issues/21#issuecomment-1951407274 to see how to avoid this issue.
dflvunoooooo commented 4 months ago

Perfekt, thank you once again!

Note also a few remarks:

  1. Yes, I read that in the docs, but in my editor tabs are replaced with spaces and it is working with python, tikz and gnuplot that way. Interesting, that it is running none the less.
  1. I yes, that is clear now. Thank you. There with the matplotlib.use('pgf') option, there is a pdf created containing only "ok".
tobiasBora commented 4 months ago
  1. For any language that does not care about indentation, it is not a problem, but python does care, what you wrote works only due to a very nasty coincidence and can have weird side effects as you experienced in the other issue. BUT in the very latest version, this is solved! You can now freely indent your python code using the very latest version, that I will release soon in CTAN as 2.6 (you can even use a fixed string in front of all lines in order to let your editor automatically indent the code without disturbing python's indentation, see the doc in additions to 2.6)