Растеризация контуров на заполненном контурном графике

У меня есть заполненный контурный график, который я хочу сохранить в виде файла .svg или .pdf. Ниже приведен упрощенный пример. Я хочу растеризовать сам контурный график (цветную часть!), Сохранив при этом все остальное (все оси, метки и т. д.) в виде векторной графики.

import numpy as np
import matplotlib.pylab as plt

x = np.linspace(0, 2*np.pi, 100)
y = np.linspace(0, 2*np.pi, 100)
xi, yi = np.meshgrid(x, y)
zi = np.cos(xi)**2 + np.sin(yi)**2

plt.figure()
plt.contourf(xi, yi, zi, rasterized=True)
plt.savefig('fig.svg', dpi=100)

Вывод

Однако, когда я просматриваю fig.svg или открываю его для редактирования в Inkscape (я могу разгруппировать заполненный контур в векторные фигуры), становится ясно, что растеризация не сработала!

Это нормально для такого простого графика, но если мой график имеет большее количество уровней контура (ниже), векторному изображению потребуется много кривых, а размер файла будет намного больше.

plt.close()
plt.figure()
plt.contourf(xi, yi, zi, 100, rasterized=True)
plt.savefig('fig.svg', dpi=100)

введите здесь описание изображения

Может кто-нибудь предложить решение и объяснить, почему этот флаг rasterized=True не сделал то, что мне нужно?


person feedMe    schedule 07.12.2017    source источник
comment
contourf() возвращает объект QuadContourSet. Этот объект, в отличие от объектов, происходящих от класса Artist, не имеет свойства растрировать.   -  person Diziet Asahi    schedule 07.12.2017


Ответы (1)


Я только что обнаружил, что это дубликат этого вопроса.

Использование rasterized=True в качестве аргумента для contour или contourf должно показать

UserWarning: The following kwargs were not used by contour: 'rasterized'

Чтобы растрировать контурный участок, необходимо растеризовать его отдельные части, т.е.

cs = plt.contour(...) 
for c in cs.collections:
    c.set_rasterized(True)

Таким образом, пример из вопроса будет выглядеть так

import numpy as np
import matplotlib.pylab as plt

x = np.linspace(0, 2*np.pi, 100)
y = np.linspace(0, 2*np.pi, 100)
xi, yi = np.meshgrid(x, y)
zi = np.cos(xi)**2 + np.sin(yi)**2

plt.figure()
cs = plt.contourf(xi, yi, zi)

for c in cs.collections:
    c.set_rasterized(True)

plt.savefig('fig.svg', dpi=100)
person Community    schedule 07.12.2017
comment
Я не вижу упомянутого вами UserWarning. Я использую python 2.7.13 и matplotlib 2.0.2 в conda 4.3.30. - person feedMe; 08.12.2017
comment
На самом деле, ваше предложение (перебор cs.collections) у меня не сработало. Вы проверили это? Мне больше повезло с методом zorder на stackoverflow.com /questions/37020842/, но мне нужно настроить это, чтобы избежать растрирования самих осей и меток. - person feedMe; 08.12.2017
comment
Да, метод здесь работает для меня. Я тестировал с matplotlib версии 2.1, но, поскольку в дубликате сообщается, что он также работает, он уже должен быть хорош с версией 1.5. До скольки не работает? - person ImportanceOfBeingErnest; 08.12.2017
comment
Это не работает настолько, что когда я открываю файл SVG в Inkscape, я вижу, что контуры по-прежнему представляют собой отдельные векторные фигуры. Я обновился до matplotlib 2.1.0 и все так же. Я использую cs = plt.contourf(xi, yi, zi, 100) for c in cs.collections: c.set_rasterized(True) plt.savefig('original.svg', dpi=100) - person feedMe; 08.12.2017
comment
Отдельные контуры по-прежнему будут отдельными элементами в файле svg, но они будут растеризованы. Таким образом, вы уже получаете коэффициент 4 в размере файла для приведенного выше кода, запускаемого с levels=100. - person ImportanceOfBeingErnest; 08.12.2017
comment
О, вы правы, это отдельные растровые фигуры, а не векторы! Извините, я пропустил это. Я не знаю почему, но я просто ожидал, что они уже будут объединены в один растр. Я не думаю, что есть быстрый встроенный способ объединить все эти растры в один? Как бы то ни было, метод zorder делает это в любом случае, и поэтому я думаю, что это лучшее решение. - person feedMe; 08.12.2017
comment
Да, в самом деле. Растеризация всего, что ниже определенного zorder, даст вам одно растровое изображение. Использование отрицательного zorder должно оставить оси векторизованными, как и в связанном ответе, верно? - person ImportanceOfBeingErnest; 08.12.2017
comment
Да, оси векторизованы как в примере! Опять же, я ожидал/хотел чего-то немного другого, то есть редактируемых текстовых меток. Как бы то ни было, текст векторизован, но в виде путей. Теперь я добавил plt.rcParams['svg.fonttype'] = 'none' в свой сценарий, как предлагается здесь latex-by-inks" title="matplotlib plot выводит текст в виде путей и не может быть преобразован в латекс чернилами"> stackoverflow.com/questions/14600948/ Кажется, теперь все так, как я хотел. Спасибо! - person feedMe; 08.12.2017