Подтвердить что ты не робот

Динамическое отображение изображения matplotlib в Интернете с использованием python

Этот вопрос задавался аналогичным образом здесь, но ответ был на мой взгляд (я супер новичок в python и веб-разработке) м надеясь на более простой способ, иначе это можно объяснить по-разному.

Я пытаюсь сгенерировать изображение с помощью matplotlib и обслуживать его без предварительной записи файла на сервер. Мой код, вероятно, глупый, но он выглядит следующим образом:

import cgi
import matplotlib.pyplot as pyplot
import cStringIO #I think I will need this but not sure how to use

...a bunch of matplotlib stuff happens....
pyplot.savefig('test.png')

print "Content-type: text/html\n"
print """<html><body>
...a bunch of text and html here...
<img src="test.png"></img>
...more text and html...
</body></html>
"""

Я думаю, что вместо того, чтобы делать pyplot.savefig('test.png'), я должен создать объект cstringIO, а затем сделать что-то вроде этого:

mybuffer=cStringIO.StringIO()
pyplot.savefig(mybuffer, format="png")

Но я довольно потерял оттуда. Все примеры, которые я видел (например, http://lost-theory.org/python/dynamicimg.html), включают в себя выполнение чего-то вроде

print "Content-type: image/png\n"

и я не понимаю, как интегрировать это с HTML, который я уже выводил.

4b9b3361

Ответ 1

Вы должны

  • сначала пишите в объект cStringIO
  • затем напишите заголовок HTTP
  • затем напишите содержимое cStringIO в stdout

Таким образом, если произошла ошибка в savefig, вы все равно можете вернуть что-то еще, даже другой заголовок. Некоторые ошибки не будут распознаваться ранее, например, некоторые проблемы с текстами, слишком большие размеры изображения и т.д.

Вам нужно сообщить savefig, где записать вывод. Вы можете сделать:

format = "png"
sio = cStringIO.StringIO()
pyplot.savefig(sio, format=format)
print "Content-Type: image/%s\n" % format
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) # Needed this on windows, IIS
sys.stdout.write(sio.getvalue())

Если вы хотите вставить изображение в HTML:

print "Content-Type: text/html\n"
print """<html><body>
...a bunch of text and html here...
<img src="data:image/png;base64,%s"/>
...more text and html...
</body></html>""" % sio.getvalue().encode("base64").strip()

Ответ 2

Мой первый вопрос: часто ли изображение меняется? Вы хотите сохранить старших? Если это вещь в реальном времени, то ваши поиски оптимизации оправданы. В противном случае выгоды от генерации изображения "на лету" не так уж важны.

Для этого кода требуется 2 запроса:

  • чтобы получить источник html, который у вас уже есть, и
  • чтобы получить фактическое изображение

Вероятно, самый простой способ (с минимальным соблюдением веб-запросов) - комментарий @Alex L, который позволит вам сделать это в одном запросе, построив HTML с встроенным в него изображением.

Ваш код будет выглядеть примерно так:

# Build your matplotlib image in a iostring here
# ......
#

# Initialise the base64 string
#
imgStr = "data:image/png;base64,"

imgStr += base64.b64encode(mybuffer)

print "Content-type: text/html\n"
print """<html><body>
# ...a bunch of text and html here...
    <img src="%s"></img>
#...more text and html...
    </body></html>
""" % imgStr

Этот код, вероятно, не будет работать из коробки, но показывает идею.

Обратите внимание, что это вообще плохая идея, если ваш образ не слишком сильно изменяется или генерация занимает много времени, потому что он будет генерироваться каждый раз.

Другой способ - создать исходный html. Загрузка будет инициировать запрос для "test.png". Вы можете обслуживать это отдельно, либо через решение для потоковой передачи буфера, которое вы уже упомянули, либо из статического файла.

Лично я придерживаюсь развязанного решения: сгенерируйте изображение другим процессом (убедитесь, что всегда есть изображение) и используйте очень легкую вещь для создания и обслуживания HTML.

НТН,

Ответ 3

Вышеуказанные ответы немного устарели - вот что работает для меня на Python3 +, чтобы получить необработанные байты данных фигуры.

import matplotlib.pyplot as plt
from io import BytesIO
fig = plt.figure()
plt.plot(range(10))
figdata = BytesIO()
fig.savefig(figdata, format='png')

Как уже упоминалось в других ответах, теперь вам нужно установить заголовок "Content-Type" в "image/png" и записать байты.

В зависимости от того, что вы используете в качестве своего веб-сервера, код может отличаться. Я использую Tornado в качестве своего веб-сервера, а код для этого:

self.set_header('Content-Type', 'image/png')
self.write(figdata.getvalue())

Ответ 4

Если я плохо неправильно понимаю ваш вопрос, все, что вам нужно сделать, это cd для местоположения изображения и запуска: python -m SimpleHTTPServer 8000 и

Затем откройте свой браузер и введите http://localhost:8000/ в строке URL.

Ответ 5

что работает для меня с python3:

buf = io.BytesIO()
plt.savefig(buf, format='png')
image_base64 = base64.b64encode(buf.getvalue()).decode('utf-8').replace('\n', '')
buf.close()