Шаг 74.
Библиотека Tkinter. Компоненты и вспомогательные классы. ... . Компонент Canvas: одновременное использование векторной графики и графики matplotlib

    На этом шаге мы рассмотрим пример одновременного использования векторной графики и графики matplotlib.

    Холст, создаваемый конструктором FigureCanvasTkAgg(), можно использовать для рисования matplotlib графики и векторной графики одновременно. Однако нужно учитывать одну особенность, которая состоит в том, что векторную графику следует создавать в процедуре обработки сообщения <Configure>. Соответствующее событие происходит, когда изменяется размер, положение или внешний вид виджета. Например, оно происходит тогда, когда окно приложения открывается после удаления перекрывающего окна другого приложения. В результате, инструкция

canvas.bind('<Configure>', myredraw, '+') 
должна добавлять к уже существующим процедурам перерисовки matplotlib-графики (они создаются вместе с классом FigureCanvasTkAgg) вашу процедуру перерисовки векторной графики.

    Ниже приведен текст примера, где используются эти два вида графики.

from tkinter import *
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk


def mydraw(event):  # векторная графика
    canvas.create_line([[0, 0], [800, 800]], fill="blue", width=3)
    canvas.create_polygon([300, 20], [340, 150], [500, 200], fill="orange")
    canvas.create_rectangle(150, 250, 220, 320, fill="cyan")
    canvas.create_image(30, 100, image=img)  # отображение картинки


def myplotcode():  # графика
    x = np.linspace(0, 2 * np.pi)
    fig = plt.figure(facecolor='white')
    ax = fig.add_subplot(111)
    ax.plot(x, np.sin(x), '-rh', linewidth=3, markersize=12, markerfacecolor='b', 
            label=r'$\ y=sin(x)$')
    ax.plot(x, -x * np.exp(-x ** 2 / 4), '-go', linewidth=3, markersize=12, 
            markerfacecolor='y',
            label=r'$ y=-x*exp(-x^2)$')
    ax.grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
    plt.legend(fontsize=12)
    plt.title('Functions graphs')
    plt.xlabel('X-ось абсцисс', {'fontname': 'Times New Roman'})
    plt.ylabel('Ордината', {'fontname': 'Times New Roman'})
    return fig


root = Tk()
root.title('Графики функций')
frm = Frame(root)
fgr = myplotcode()
canvasAgg = FigureCanvasTkAgg(fgr, master=frm)  # составной холст
canvasAgg.draw()
canvas = canvasAgg.get_tk_widget()  # объект стандартного холста
canvas.pack(fill=BOTH, expand=1)
frm.pack(fill=BOTH, expand=1)
# создание объекта img для отображение картинки 
images = "van.gif"
img = PhotoImage(file=images)
canvas.bind('<Configure>', mydraw, '+')
toolbar = NavigationToolbar2Tk(canvasAgg, root)
toolbar.update()
root.mainloop()
Архив с файлами можно взять здесь.

    Программа начинается с импортирования необходимых модулей и функций. Далее мы создаем две функции. В первой из них (mydraw) вызываются графические функции стандартного холста canvas. Вторая (myplotcode) - демонстрирует использование различных двумерных графических функций модуля matplotlib.pyplot:

def mydraw(event):  # векторная графика
    canvas.create_line([[0, 0], [800, 800]], fill="blue", width=3)
    canvas.create_polygon([300, 20], [340, 150], [500, 200], fill="orange")
    canvas.create_rectangle(150, 250, 220, 320, fill="cyan")
    canvas.create_image(30, 100, image=img)  # отображение картинки


def myplotcode():  # графика
    x = np.linspace(0, 2 * np.pi)
    fig = plt.figure(facecolor='white')
    ax = fig.add_subplot(111)
    ax.plot(x, np.sin(x), '-rh', linewidth=3, markersize=12, markerfacecolor='b', 
            label=r'$\ y=sin(x)$')
    ax.plot(x, -x * np.exp(-x ** 2 / 4), '-go', linewidth=3, markersize=12, 
            markerfacecolor='y',
            label=r'$ y=-x*exp(-x^2)$')
    ax.grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
    plt.legend(fontsize=12)
    plt.title('Functions graphs')
    plt.xlabel('X-ось абсцисс', {'fontname': 'Times New Roman'})
    plt.ylabel('Ордината', {'fontname': 'Times New Roman'})
    return fig

    Затем мы создаем объект окна root и контейнерный элемент Frame. Вызов функции myplotcode() создает matplotlib-графику и возвращает объект графического окна fgr:

root = Tk()
root.title('Графики функций')
frm = Frame(root)
fgr = myplotcode()

    Потом fgr передается первым аргументом конструктору FigureCanvasTkAgg(). Он создает объект составного холста на родительском виджете frm. Инструкция canvasAgg.draw() отображаеет matplotlib-графику:

canvasAgg = FigureCanvasTkAgg(fgr, master=frm)  # составной холст
canvasAgg.draw()

    Используя метод canvasAgg.get_tk_widget(), мы получаем ссылку canvas на объект "стандартного" холста Canvas. Она используется при его размещении упаковщиком pack(). Следом размещаем виджет-рамку и создаем объекта img, который используется в функции mydraw() при отображении изображения.

canvas = canvasAgg.get_tk_widget()  # объект стандартного холста
canvas.pack(fill=BOTH, expand=1)
frm.pack(fill=BOTH, expand=1)
# создание объекта img для отображение картинки 
images = "van.gif"
img = PhotoImage(file=images)

    Инструкция

canvas.bind('<Configure>', mydraw, '+')
добавляет функцию mydraw() к обработке события <Configure>, которое первый раз происходит при открытии окна программы, а затем каждый раз, когда окно меняет размер, положение или становится видимым после смещения или удаления перекрывающего окна другой программы.

    В завершении мы добавляем стандартную панель с кнопками управления matplotlib-графикой.

toolbar = NavigationToolbar2Tk(canvasAgg, root)
toolbar.update()

root.mainloop()

    Окно программы показано на рисунке 1.


Рис.1. Результат работы приложения

    Попробуйте менять его размер, а также протестируйте работу кнопок панели NavigationToolbar2Tk. Они управляют только matplotlib-графикой.

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг