Название картинки в блокнотах Google Colab или Jupyter
В блокноте Google colab у меня формируется некий график, который я хочу сохранить на свой компьютер. Если я нажимаю на правую кнопку мыши и выбираю пункт выпадающего меня "Сохранить картинку как...", то название файла по умолчанию "Без названия". Я бы хотел, чтобы предлагаемое по умолчанию название было бы таким, каким я его назову в коде. Видимо, такая же проблема и в Jupiter. Подскажите, пожалуйста, как это можно сделать?
Ответы (1 шт):
В ноутбуке, будь то Jupyter Notebook или Google Colab, графики отображаются как Data URL. В этой схеме нет возможности задать имя по умолчанию для сохранения картинки. Браузер попытается вычленить имя либо из HTTP-заголовка Content-Disposition, либо из URL-адреса. Следовательно, чтобы решить задачу в лоб, нужно сохранить картинку на доступном онлайн-ресурсе под заданным именем и использовать адрес доступа к ней при отображении в блокноте.
Я полагаю, что будет проще видоизменить задачу, не требуя определенного имени по умолчанию при сохранении через контекстное меню Save Image As.... Например, картинку, представленную как Data URL, мы могли бы упаковать в HTML-ссылку, снабдив последнюю параметром download="произвольное_имя.png"
. Тогда при нажатии на картинку левой кнопкой мыши, будет предложено сохранить ссылку (т.е. картинку в виде Data URL) как "произвольное_имя.png"
:
import numpy as np
from matplotlib import pyplot as plt
from IPython.display import display_html
from base64 import b64encode
from io import BytesIO
y = np.random.randn(100)
x = range(len(y))
data = BytesIO()
plt.plot(x, y)
plt.savefig(data)
plt.close() # не выводить график под ячейкой
img = f'data:image/png;base64,{b64encode(data.getvalue()).decode()}'
fname = 'graph_of_X_vs_Y.png'
hint = 'Left click to save' # подсказка при наведении мышки на картинку
msg = f'<a href="{img}" download="{fname}"><img src="{img}" title="{hint}"></a>'
display_html(msg, raw=True)
Как вариант, мы могли бы переписать код в виде процедуры:
def display_image(img, fname=None, hint="Left click to save"):
"""Show the given `img` picture in a notebook as a downlodable link
with `fname` a default file name to save as, and a `hint` message
to show when a mouse cursor is over the picture.
img: a file name as a string or `Path` or a file object with an image.
fname: a default name to use when saving the picture; if it's None
and `img` is a file name or a file object with a `name` attribute,
then the latter will be used as `fname`, otherwise some arbitrary
name will be supplied and image type detected if possible (image
type is supposed to be PNG by default; png, jpg, jpeg, webp can
be detected and displayed).
"""
from base64 import b64encode
from IPython.display import display_html
from io import BufferedIOBase
from pathlib import Path
from matplotlib import rcParams
DEFAULT_NAME = 'plot.%s'
DEFAULT_EXT = rcParams['savefig.format']
if isinstance(img, str) or isinstance(img, Path):
img = Path(img)
assert img.exists() and img.is_file(), "Path to an image isn't relevant"
if fname is None:
fname = img.name
with open(img, 'br') as f:
img = f.read()
elif isinstance(img, BufferedIOBase) and img.readable() and img.seekable():
img.seek(0)
if fname is None:
if isinstance(getattr(img, 'name', None), str):
fname = img.name
else:
try:
import imghdr # python>=3.13: pip install standard-imghdr
ext = imghdr.what(img) or DEFAULT_EXT
except ImportError:
ext = DEFAULT_EXT
fname = DEFAULT_NAME % ext
img = img.read()
else:
raise ValueError('Not supported image data')
img = f'data:image;base64,{b64encode(img).decode()}'
msg = f'<a href="{img}" download="{fname}"><img src="{img}" title="{hint}"></a>'
display_html(msg, raw=True)
И тогда вывод графика на экран мог бы выглядеть, например, так:
import numpy as np
import matplotlib.pyplot as plt
y = np.random.randn(100)
x = range(len(y))
fname = 'plotXvsY.jpg'
plt.plot(x, y)
plt.savefig(fname)
plt.close()
display_image(fname)