Matplotlib: добавьте изображение в верхний левый угол рисунка

Я пробовал различные методы, найденные в Интернете, но не смог добавить изображение в правильное место в верхнем левом углу фигуры.

Вот одна из моих попыток, где я пытаюсь установить точный размер сгенерированной фигуры в пикселях, а затем добавляю изображение размером 48x48 пикселей в верхний левый угол. Проблемы:

  • Фигуры не создаются с выбранным размером пикселей.
  • По оси X, где находится начало координат, мне нужно сместиться на 34 пикселя, чтобы изображение было близко к левой границе, что для меня не имеет смысла.
  • По оси Y изображение также размещено плохо, в основном потому, что размер не соответствует ожидаемому.

Почему приведенный ниже код не работает? Как я могу достичь того, чего хочу?

import matplotlib.pylab as plt                               # Plot
from PIL import Image                                        # Add background image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage # Add background image

def plot_image(w, h):
  px         = 1/plt.rcParams['figure.dpi']           
  fig,ax     = plt.subplots(figsize=(w*px, h*px))

  image_path = '......../The Simpsons 48x48.png'
  image_data = Image.open(image_path)
  image_box  = OffsetImage(image_data, zoom=1)
  anno_box   = AnnotationBbox(image_box, xy=(34,h-48), xycoords='figure pixels', frameon=False)
  ax.add_artist(anno_box)

  plt.text(0.5, 0.5, f'Requested: {w}x{h}')
  plt.text(0.5, 0.4, 'Obtained: 579x455' if w==640 else
                     'Obtained: 759x561' if w==800 else 
                     'Obtained: 960x711' )
  plt.show()

plot_image( 640, 480)
plot_image( 800, 600)
plot_image(1024, 768)

Полученные результаты:

Использованное изображение:

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
101
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Все дело в понимании размера изображения. Сначала убедитесь, что размер фигуры установлен правильно в пикселях, а затем правильно поместите изображение в верхний левый угол, используя AnnotationBbox. Вот как вам следует это сделать:

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage

def plot_image(w, h):
    px = 1 / plt.rcParams['figure.dpi']  
    fig, ax = plt.subplots(figsize=(w * px, h * px))

    image_path = r"C:\Users\serge.degossondevare\Downloads\homer.png"  
    image_data = Image.open(image_path)

    image_box = OffsetImage(image_data, zoom=1)
    anno_box = AnnotationBbox(image_box, xy=(0, 1), xycoords='axes fraction', 
                              box_alignment=(0, 1), frameon=False)
    ax.add_artist(anno_box)

    plt.text(0.5, 0.5, f'Requested: {w}x{h}', ha='center', va='center')
    plt.text(0.5, 0.4, f'Obtained: {int(fig.bbox.width)}x{int(fig.bbox.height)}', ha='center', va='center')

    ax.set_axis_off()

    plt.show()

plot_image(640, 480)
plot_image(800, 600)
plot_image(1024, 768)

что дает вам

Если вы хотите, чтобы изображение Гомера было пропорционально уменьшено до холста:

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage

def plot_image(w, h, image_path):
    px = 1 / plt.rcParams['figure.dpi']
    fig, ax = plt.subplots(figsize=(w * px, h * px))

    image_data = Image.open(image_path)
    
    zoom_factor = min(w / image_data.width, h / image_data.height) * 0.1  

    image_box = OffsetImage(image_data, zoom=zoom_factor)
    anno_box = AnnotationBbox(image_box, xy=(0, 1), xycoords='axes fraction', 
                              box_alignment=(0, 1), frameon=False)
    ax.add_artist(anno_box)

    plt.text(0.5, 0.5, f'Requested: {w}x{h}', ha='center', va='center')
    plt.text(0.5, 0.4, f'Obtained: {int(fig.bbox.width)}x{int(fig.bbox.height)}', ha='center', va='center')

    ax.set_axis_off()

    plt.show()

image_path = r"C:\Users\serge.degossondevare\Downloads\homer.png"
plot_image(640, 480, image_path)
plot_image(800, 600, image_path)
plot_image(1024, 768, image_path)

который дает

Тогда масштабирование зависит от вас.

Спасибо. Мне еще предстоит многое узнать об этом AnnotationBbox. Однако: <br/> 1. Изображения выше не соответствуют ожиданиям. Размер сбился. <img src = "i.sstatic.net/Ol7hMw81.png " alt = " i.sstatic.net/Ol7hMw81.png" width = "627" height = "474" class = "shrinkToFit"> для изображения 800x600. <br/> 2- Вставленное изображение не выровнено.

Chris 07.06.2024 14:22

Тогда вам следует опубликовать то, что вы ожидаете.

Serge de Gosson de Varennes 07.06.2024 14:24

Извините за форматирование. Я понятия не имею, как форматировать ответ. Если форматирование вообще возможно.

Chris 07.06.2024 14:29

Я обновил альтернативу, которая пропорционально масштабируется по холсту.

Serge de Gosson de Varennes 07.06.2024 14:30

К сожалению, обновление по-прежнему не создает изображения с ожидаемым разрешением и не выравнивает края.

Chris 07.06.2024 14:38

Также Гомер, кажется, добавлен размером примерно 85x85 пикселей.

Chris 07.06.2024 14:40

Хорошо, похоже, проблема в том, что моя IDE некорректно отображает сгенерированные изображения, как указал RuthC. Какую IDE вы используете, где не нужно сохранять изображение для его корректного просмотра?

Chris 08.06.2024 03:37

@Chris Я думаю, что у Сержа та же проблема: если вы проверите изображения, размещенные в этом ответе, они не будут иметь правильный размер.

RuthC 08.06.2024 14:20

Да, именно это я и пытался подчеркнуть, предоставив HTML-код графиков, загруженных Сержем. Использование AnnotationBbox неправильно позиционирует изображение и неправильно определяет размер вставленного изображения. Очень обидно для такой зрелой библиотеки. И очень разочаровывает то, что среды разработки Python не могут даже правильно отображать созданные изображения. Кажется, это такая базовая функция.

Chris 09.06.2024 04:31
Ответ принят как подходящий

Вы пользуетесь блокнотом? Когда вы показываете в блокноте, размер фигуры автоматически изменяется, чтобы соответствовать изображенным на ней художникам. Это эквивалентно передаче bbox_inches='tight' при вызове savefig . Это можно отключить в блокноте, но я только что попробовал заменить plt.show() в вашем примере на plt.savefig(f'simpson_test{w}x{h}.png'), и все они получились нужного размера.

Я не понял, почему позиционирование у AnnotationBbox странное, но есть более простой способ figimage:

import matplotlib.pyplot as plt                              # Plot
from PIL import Image                                        # Add background image

def plot_image(w, h):
  px         = 1/plt.rcParams['figure.dpi']           
  fig,ax     = plt.subplots(figsize=(w*px, h*px))

  image_path = 'simpson.png'
  image_data = Image.open(image_path)
  fig.figimage(image_data, yo=h-48)

  plt.text(0.5, 0.5, f'Requested: {w}x{h}')
  plt.savefig(f'simpson_test{w}x{h}.png')

plot_image( 640, 480)
plot_image( 800, 600)
plot_image(1024, 768)

Я использую VS Code. Что ты используешь? Я пробовал использовать PyCharm, но он не находит библиотеки, импортирующие matplotlib.pylab как plt # Plot ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ModuleNotFoundError: нет модуля с именем matplotlib.

Chris 08.06.2024 02:01

Гррр. VS Code не только неправильно отображает размер, но и не может правильно позиционировать Гомера.

Chris 08.06.2024 02:43

Хорошо, я переустановил matplotlib из PyCharm (зачем мне это делать?). Когда я запускаю код, он открывает окно под названием «Рисунок 1», в котором также отображается совершенно ошибочное изображение. Эти инструменты кажутся такими древними и простыми. Не можете даже правильно отобразить картинку? Действительно? Напоминает мне времена, когда единственным возможным результатом работы мэйнфрейма была бумага. :-( Любая IDE Python, которая может правильно отображать изображения? Теперь PyCharm может запускать мой код, но не ваш. Gtk-Message: 12:49:45.182: Не удалось загрузить модуль «xapp-gtk3-module»

Chris 08.06.2024 02:46

figimage(), похоже, отлично справляется со своей задачей. Спасибо. Не могу поверить, что потратил все это время на создание изображения, которое не соответствует реальному результату. Я проведу еще несколько тестов и отмечу ваш повтор как ответ.

Chris 08.06.2024 03:53

Боюсь, я на самом деле не использую IDE, а просто запускаю свои скрипты из командной строки.

RuthC 08.06.2024 10:24

Я только сейчас заметил, что в этом примере используется pylab. Это не рекомендуется, поэтому я обновил импорт для использования pyplot.

RuthC 08.06.2024 11:34

Другие вопросы по теме