nschloe / tikzplotlib

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

matplotlibs polar plot -> pgfplots polaraxis #11

Open twmr opened 12 years ago

twmr commented 12 years ago

A matlab/matplotlib polar plot should be converted into a polaraxis object of pgfplots

width, height = matplotlib.rcParams['figure.figsize']
size = min(width, height)
# make a square figure
fig = figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
dat = np.genfromtxt(fname)
ax.plot(dat[:,0],dat[:,1])

#does not work
tikz_save('myfile.tex' );
zsoerenm commented 8 years ago

+1 It currently results into this error:

KeyError('bottom',)
  File "/usr/lib/python3.5/site-packages/matplotlib2tikz/save.py", line 134, in save
    data, content = _recurse(data, figure)
  File "/usr/lib/python3.5/site-packages/matplotlib2tikz/save.py", line 218, in _recurse
    ax = axes.Axes(data, child)
  File "/usr/lib/python3.5/site-packages/matplotlib2tikz/axes.py", line 221, in __init__
    axcol = obj.spines['bottom'].get_edgecolor()
kurhar commented 5 years ago
import matplotlib.pyplot as plt
plt.polar(1,1)
ax = plt.gca()
print(ax.spines)

Returns:

OrderedDict([('polar', <matplotlib.spines.Spine at 0x1e8037d59e8>),
             ('start', <matplotlib.spines.Spine at 0x1e8037d5b00>),
             ('end', <matplotlib.spines.Spine at 0x1e8037d5c18>),
             ('inner', <matplotlib.spines.Spine at 0x1e8037d5d30>)])

While

import matplotlib.pyplot as plt
plt.plot(1,1)
ax = plt.gca()
print(ax.spines)

Returns:

OrderedDict([('left', <matplotlib.spines.Spine at 0x1e8039d8ef0>),
             ('right', <matplotlib.spines.Spine at 0x1e8039d8c50>),
             ('bottom', <matplotlib.spines.Spine at 0x1e8025af780>),
             ('top', <matplotlib.spines.Spine at 0x1e8039c2c18>)])

You hack it a bit and create:

ax.spines["bottom"] = ax.spines["inner"]

And get (for the polar plot):

OrderedDict([('polar', <matplotlib.spines.Spine at 0x1e803ad38d0>),
             ('start', <matplotlib.spines.Spine at 0x1e8039d8be0>),
             ('end', <matplotlib.spines.Spine at 0x1e803ac9fd0>),
             ('inner', <matplotlib.spines.Spine at 0x1e803ac9e48>),
             ('bottom', <matplotlib.spines.Spine at 0x1e803ac9e48>)])

tikz_save does not fail, but it creates a cartesian version of the plot! So I guess if the coordinate system transformations syntax is adapted to polar, \begin{polaraxis} is used and the spine names are adapted then it could work.

senselessDev commented 4 years ago

A quick and dirty workaround:

import matplotlib.pyplot
import numpy
import tikzplotlib
ax = matplotlib.pyplot.subplot(111) # no projection='polar' here
x_grid = numpy.linspace(0, 360, 100, endpoint=False)
ax.plot(x_grid, numpy.random.random(100))
tikzplotlib.save('example.tex',
                 standalone=True,
                 extra_axis_parameters=[r'xticklabel shift=5pt',
                                        r'xticklabel=$\pgfmathprintnumber{\tick}\si{\degree}$'])
with open('example.tex', 'r') as file:
        filedata = file.read()

filedata = filedata.replace(r'\begin{document}', r'\usepackage{siunitx} \usepgfplotslibrary{polar} \begin{document}')
filedata = filedata.replace('{axis}', '{polaraxis}')

with open('example.tex', 'w') as file:
    file.write(filedata)

Note that the plot is not polar in matplotlib, but a quick replacement in the generated TeX-Code makes a polar plot from it with TikZ.

Oklahomawhore commented 1 year ago

+1 , my graph is :

# Create sample Series
series1 = vec_trigger_model
series2 = vec_clean_model

# Set the categories (variables) for the radar plot
categories = series1.index

# Create a figure and axis for the radar plot
fig, ax = plt.subplots(figsize=(8, 6), subplot_kw={'projection': 'polar'})

# Convert values to radians
theta = np.linspace(0, 2*np.pi, len(categories) + 1, endpoint=True)

# Plot data for Series 1
values1 = series1.values
values1_closed = np.concatenate([values1, [values1[0]]])
ax.plot(theta, values1_closed, label='backdoored models')
ax.fill(theta, values1_closed, alpha=0.2)

# Plot data for Series 2
values2 = series2.values
values2_closed = np.concatenate([values2, [values2[0]]])
ax.plot(theta, values2_closed, label='clean models')
ax.fill(theta, values2_closed, alpha=0.2)

# Set the labels for each category
ax.set_xticks(theta[:-1], categories,)
ax.set_xticklabels(categories,fontsize=14.0)

label_text = []
for i, label in enumerate(ax.get_xticklabels()):
    label.set_y(-0.0)
    if i == 0:
        label.set_y(-0.05)
    elif i==1:
        label.set_y(-0.05)
    elif i==2:
        label.set_y(-0.05)
    elif i == 3:
        label.set_y(-0.3)
    elif i == 4:
        label.set_y(-0.07)
    elif i == 5:
        label.set_y(-0.05)

# Set the radial grid
ax.set_rgrids([30, 60, 90], labels=['30', '60', '90'], angle=45)

# Add legend
ax.legend(loc='best')

# Add a title
# plt.title('Comparison between inverse backdoored and clean model, accuracy averaged over five datasets')

# Show the radar plo

import tikzplotlib
tikzplotlib.clean_figure()
tikzplotlib.save("radar.tex")

generates the following error:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[9], line 60
     58 import tikzplotlib
     59 tikzplotlib.clean_figure()
---> 60 tikzplotlib.save("radar.tex")

File ~/miniconda3/envs/ML-base/lib/python3.8/site-packages/tikzplotlib/_save.py:262, in save(filepath, encoding, *args, **kwargs)
    252 def save(filepath: str | Path, *args, encoding: str | None = None, **kwargs):
    253     """Same as `get_tikz_code()`, but actually saves the code to a file.
    254 
    255     :param filepath: The file to which the TikZ output will be written.
   (...)
    260     :returns: None
    261     """
--> 262     code = get_tikz_code(*args, filepath=filepath, **kwargs)
    263     with open(filepath, "w", encoding=encoding) as f:
    264         f.write(code)

File ~/miniconda3/envs/ML-base/lib/python3.8/site-packages/tikzplotlib/_save.py:213, in get_tikz_code(figure, filepath, axis_width, axis_height, textsize, tex_relative_path_to_data, externalize_tables, override_externals, externals_search_path, strict, wrap, add_axis_environment, extra_axis_parameters, extra_groupstyle_parameters, extra_tikzpicture_parameters, extra_lines_start, dpi, show_info, include_disclaimer, standalone, float_format, table_row_sep, flavor)
    210     _print_pgfplot_libs_message(data)
    212 # gather the file content
--> 213 data, content = _recurse(data, figure)
    215 # Check if there is still an open groupplot environment. This occurs if not
    216 # all of the group plot slots are used.
    217 if "is_in_groupplot_env" in data and data["is_in_groupplot_env"]:

File ~/miniconda3/envs/ML-base/lib/python3.8/site-packages/tikzplotlib/_save.py:339, in _recurse(data, obj)
    336     continue
    338 if isinstance(child, mpl.axes.Axes):
--> 339     ax = _axes.Axes(data, child)
    341     if ax.is_colorbar:
    342         continue

File ~/miniconda3/envs/ML-base/lib/python3.8/site-packages/tikzplotlib/_axes.py:144, in Axes.__init__(self, data, obj)
    140 self._grid(obj, data)
    142 # axis line styles
    143 # Assume that the bottom edge color is the color of the entire box.
--> 144 axcol = obj.spines["bottom"].get_edgecolor()
    145 data, col, _ = _color.mpl_color2xcolor(data, axcol)
    146 if col != "black":

File ~/miniconda3/envs/ML-base/lib/python3.8/site-packages/matplotlib/spines.py:574, in Spines.__getitem__(self, key)
    570     else:
    571         raise ValueError(
    572             'Spines does not support slicing except for the fully '
    573             'open slice [:] to access all spines.')
--> 574 return self._dict[key]

KeyError: 'bottom'