nschloe / tikzplotlib

:bar_chart: Save matplotlib figures as TikZ/PGFplots for smooth integration into LaTeX.
MIT License
2.41k stars 214 forks source link

Feature request: only keep essential options, and put data into one file #435

Open liboyue opened 4 years ago

liboyue commented 4 years ago

Hi, this is a great library that can save me tones of time! I wish I had discovered it earlier. I use pgfplots heavily, but inputing data is a nightmare when plotting a lot of curves. tikzplotlib easily solves this problem. But there are several easy improvements that could be included.

  1. The data can be put into one .tex file. Imagine I have four 1 x 4 figures , each subfigure has 6 curves. Thats 4 x 4 x 6 = 96 .tsv files in total, which is hard to manage. It may be better to use filecontents like
    
    % test1-data.tex
    \begin{filecontents}{test1-000.tsv}
    ...
    \end{filecontents}

\begin{filecontents}{test1-001.tsv} ... \end{filecontents}

In the main file, 

% main.tex ... \input{test1-data.tex} ...


2. `tikzplotlib` produces too many configurations to make the pdf look exactly like the matplotlib figure, but lacks the option for users to configure which configuration to have or not have. I can patch the functions, but it may be a useful feature for other people.

test.py

import matplotlib.pyplot as plt import numpy as np import tikzplotlib

x = np.linspace(0, 2 * np.pi, 400) y = np.sin(x ** 2) fig, axs = plt.subplots(2, 2) axs[0, 0].plot(x, y) axs[0, 0].set_title('Axis [0,0]') axs[0, 1].plot(x, y, 'tab:orange') axs[0, 1].set_title('Axis [0,1]') axs[1, 0].plot(x, -y, 'tab:green') axs[1, 0].set_title('Axis [1,0]') axs[1, 1].plot(x, -y, 'tab:red') axs[1, 1].set_title('Axis [1,1]')

for ax in axs.flat: ax.set(xlabel='x-label', ylabel='y-label')

Hide x labels and tick labels for top plots and y ticks for right plots.

for ax in axs.flat: ax.label_outer()

def patch():

def _new_draw_line2d(data, obj):
    content = ["\\addplot +[mark=none] "] + tikzplotlib._line2d._table(obj, data)[0]
    legend_text = tikzplotlib._util.get_legend_text(obj)
    if legend_text is not None:
        content.append(f"\\addlegendentry{{{legend_text}}}\n")
    return data, content

def _new_init(self, data, obj):
    _tmp(self, data, obj)
    self.axis_options = [x for x in self.axis_options if 'mod' in x or 'label' in x or 'title' in x]

_tmp = tikzplotlib._axes.Axes.__init__
tikzplotlib._axes.Axes.__init__ = _new_init
tikzplotlib._line2d.draw_line2d = _new_draw_line2d

tikzplotlib.save("test1.tex", standalone=True, externalize_tables=True)

patch() tikzplotlib.save("test2.tex", standalone=True, externalize_tables=True)


`test1.pdf`
![image](https://user-images.githubusercontent.com/5857249/91592285-4abdb180-e92c-11ea-9202-8cabf4d3428b.png)

`test2.pdf`
![image](https://user-images.githubusercontent.com/5857249/91592256-41344980-e92c-11ea-8e91-415deb9f0b90.png)
nschloe commented 3 years ago

I don't quite understand either of your points. What does filecontents do? And what's hard to manage?

Also, I'm not sure why one would only want to keep a subset of options. You can style mpl to get all blue curves, too, right?