Это одна из самых запутанных частей в попытке получить точные значения пикселей из matplotlib.Matplotlib отделяет средство визуализации, которое обрабатывает точные значения пикселей от холста, на котором нарисованы фигура и оси.
По сути, средство визуализации, существующее при первоначальном создании фигуры (но еще не отображаемое), не обязательно совпадает с средством визуализации, которое используется при отображении фигуры или сохранении ее в файл.
То, что вы делаете, правильно, но оно использует начальный рендер, а не тот, который используется при сохранении фигуры.
Чтобы проиллюстрировать это, вот несколько упрощенная версия вашего кода:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(np.random.random((27,27)), interpolation='nearest')
for i in range(28):
x, y = ax.transData.transform_point([i,i])
print '%i, %i' % (x, fig.bbox.height - y)
fig.savefig('foo.png', dpi=fig.dpi)
Это дает результаты, аналогичные тем, что у вас есть выше: (Различия связаны с различными бэкэндами рендеринга между вашим компьютером.и мой)
89, 55
107, 69
125, 83
...
548, 410
566, 424
585, 439
Однако, если мы сделаем то же самое, но вместо этого нарисуем фигуру перед отображением координат, мы получим правильный ответ!
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(np.random.random((27,27)), interpolation='nearest')
fig.canvas.draw()
for i in range(28):
x, y = ax.transData.transform_point([i,i])
print '%i, %i' % (x, fig.bbox.height - y)
fig.savefig('foo.png', dpi=fig.dpi)
Это дает:(Имейте в виду, что край фигуры находится в <-0.5, -0.5>
в координатах данных, а не <0, 0>
. (Т. Е. Координаты для построенного изображения центрированы по пикселям). Поэтому <0, 0>
дает 143, 55
, а не135, 48
)
143, 55
157, 69
171, 83
...
498, 410
512, 424
527, 439
Конечно, рисование фигуры только для того, чтобы нарисовать ее снова, когда она сохранена, является избыточным и вычислительно дорогим.
Чтобы избежать рисования дважды, вы можете подключить обратный вызовфункция к событию рисования, и вывести свою карту изображения HTML внутри этой функции.В качестве быстрого примера:
import numpy as np
import matplotlib.pyplot as plt
def print_pixel_coords(event):
fig = event.canvas.figure
ax = fig.axes[0] # I'm assuming there's only one subplot here...
for i in range(28):
x, y = ax.transData.transform_point([i,i])
print '%i, %i' % (x, fig.bbox.height - y)
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(np.random.random((27,27)), interpolation='nearest')
fig.canvas.mpl_connect('draw_event', print_pixel_coords)
fig.savefig('foo.png', dpi=fig.dpi)
, который дает правильный вывод, при этом рисуя фигуру только один раз, когда она сохраняется:
143, 55
157, 69
171, 83
...
498, 410
512, 424
527, 439
Еще одним преимуществом является то, что вы можете использовать любой dpiв вызове fig.savefig
без необходимости предварительно вручную устанавливать dpi объекта fig
.Следовательно, при использовании функции обратного вызова вы можете просто сделать fig.savefig('foo.png')
, (или fig.savefig('foo.png', dpi=whatever)
), и вы получите вывод, который соответствует сохраненному файлу .png.(Значение dpi по умолчанию при сохранении фигуры равно 100, а значение dpi по умолчанию для объекта фигуры равно 80, поэтому сначала нужно было указать значение dpi, равное fig.dpi
))
Надеюсь, это хоть немного понятно!