tkinterをtkinterのcanvasにmatplotlibを表示。
import sys
import os
import configparser
import csv
from pprint import pprint
from math import sqrt
import numpy as np
from scipy import optimize
from tkinter import *
from tkinter import ttk
from tkinter import filedialog, messagebox
import matplotlib
# https://qiita.com/TomokIshii/items/3a26ee4453f535a69e9e
# Renderere
Filetypes Description
# AGG
png raster
grapahics - high quality images using the Anti-Grain Geometry engine
# PS ps eps
vector graphics - Postscript output
# PDS pdf
vector graphics - Portable Document Format
# SVG svg
vector graphics - Scalable Vector Graphics
# Cairo png ps pdf svg... vector graphics - Cairo graphics
# GDK png jpg tiff... raster graphics - the Gimp
Drawing Kit
matplotlib.use('TkAgg') matplotlibのbackendとしてTkAggを使う
(AGG: Anti-Grain Geometry engine)
from matplotlib import pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlibのtkagg ackendモジュールから、tkinter.Canvasに変換する関数をimport
#=============================
# 大域変数の定義
#=============================
# フィッティングパラメータ初期値。線形最小二乗の場合は適当
ai0 = [0, 0, 0]
xrange = [0, 10]
# グラフ設定
font_size = 24
# 全体設定
window_size = "500x200"
ini_dir = os.path.abspath(os.path.dirname(__file__))
file_type = [('CSV file', '*.csv')]
# 起動時引数でデータ/設定ファイル名を受け取る
datafile = None
inifile = None
argv = sys.argv
if len(argv) >= 2:
path = argv[1]
datafile = os.path.splitext(path)[0] + '.csv'
inifile = os.path.splitext(path)[0] + '.prm'
fit_order = 2
#=============================
# functions
#=============================
def eprint(textbox, *args):
print(*args, end = '')
textbox.insert('end', *args)
#=============================
# csvファイルの読み込み
#=============================
def read_ini(path, obj):
config = configparser.ConfigParser()
if config.read(path):
obj['x0'] = config.get('data', 'x0')
obj['x1'] = config.get('data', 'x1')
obj['inipath'] = path
return config
return None
#=============================
# csvファイルの読み込み
#=============================
def read_csv(path, obj):
i = 0
x = []
y = []
with open(path, "r") as f:
reader = csv.reader(f)
for row in reader:
if i == 0:
header = row
else:
xi = float(row[0])
x.append(xi)
y.append(float(row[1]))
i += 1
obj['datapath'].set(path)
obj['savepath'].set(os.path.splitext(path)[0] + '-fit.csv')
obj['header'] = header
obj['x'] = x
obj['y'] = y
obj['title'].set(path)
obj['xlabel'].set(header[0])
obj['ylabel'].set(header[1])
textbox = obj['outputtext']
eprint(textbox, "\n")
eprint(textbox, "CSV data:\n")
eprint(textbox, " header: {}\n".format(header))
eprint(textbox, " x: {}\n".format(x))
eprint(textbox, " y: {}\n".format(y))
return header, x, y
#=============================
# File=>openメニュー、pathボタン
#=============================
def path_button_click(obj):
selpath = filedialog.askopenfilename(filetypes = file_type, initialdir = ini_dir)
obj['datapath'].set(selpath)
header, x, y = read_csv(selpath, obj)
obj['x0'].set(min(x))
obj['x1'].set(max(x))
#=============================
# scipy.optimize()による最小化
#=============================
def lsq_button_click(obj):
eprint(obj['outputtext'], "\n")
eprint(obj['outputtext'], "polynomial fit by scipy.optimize() start:\n")
x = obj['x']
y = obj['y']
x0 = obj['x0'].get()
x1 = obj['x1'].get()
xf = []
yf = []
for i in range(len(x)):
if x0 <= x[i] <= x1:
xf.append(x[i])
yf.append(y[i])
# leastsqの戻り値は、最適化したパラメータのリストと、最適化の結果
ret = np.polyfit(x, y, deg = obj['fit_order'].get(), full = True)
ai = ret[0]
res = sqrt(ret[1][0] / len(x))
eprint(obj['outputtext'], " lsq result: ai={}\n".format(ai))
eprint(obj['outputtext'], " residual={}\n".format(res))
#=============================
# グラフの表示
#=============================
#表示データの作成
ncal = 100
xmin = min(x)
xmax = max(x)
xstep = (xmax - xmin) / (ncal - 1)
xc = []
yc = []
for i in range(ncal):
xi = xmin + i * xstep
yi = np.poly1d(ai)(xi)
xc.append(xi)
yc.append(yi)
#グラフの作成、表示
fontsize = obj['font_size'].get()
canvas = obj['canvas']
figure = obj['figure']
figure.clf()
ax = figure.add_subplot(111)
ax.plot(x, y, label = 'raw data', marker = 'o', linestyle = 'None')
ax.plot(xc, yc, label = 'fitted', linestyle = 'dashed')
ax.set_title(obj['title'].get(), fontsize = fontsize)
ax.set_xlabel(obj['xlabel'].get(), fontsize = fontsize)
ax.set_ylabel(obj['ylabel'].get(), fontsize = fontsize)
ax.legend(fontsize = fontsize)
ax.tick_params(labelsize = fontsize)
figure.tight_layout()
canvas.draw()
def main():
print('Second-order polynomial lsq')
# Base variables
obj = {}
root = Tk()
root.option_add('*font', ('FixedSys', 14))
pw = PanedWindow(root, sashwidth = 4) Root
windowを左右に分割するPaned Windowを使う
pw.pack(expand = True, fill = BOTH)
# Left frame
設定画面用
left_frame = ttk.Frame(root)
pw.add(left_frame)
# Right frame
matplotlibのcanvasを表示
right_frame = ttk.Frame(root)
pw.add(right_frame)
# tkinter variabls
obj['inipath'] = StringVar()
obj['datapath'] = StringVar()
obj['savepath'] = StringVar()
obj['x0'] = DoubleVar(value = xrange[0])
obj['x1'] = DoubleVar(value = xrange[1])
obj['title'] = StringVar()
obj['xlabel'] = StringVar()
obj['ylabel'] = StringVar()
obj['font_size'] = IntVar(value = font_size)
obj['fit_order'] = IntVar(value = fit_order)
obj['output'] = StringVar()
root.title('Second-order polynomial lsq')
root.minsize(200, 200)
# Menu
menu_bar = Menu(root)
menu_file = Menu(menu_bar, tearoff = 0)
menu_file.add_command(label='Open', accelerator='Ctrl+O',
command = lambda: path_button_click(obj))
menu_file.add_command(label='exit', accelerator='Alt+E',
command = lambda: exit())
menu_bar.add_cascade(label = 'File', menu = menu_file)
root.config(menu = menu_bar)
root.grid()
# Canvas (right)
# figure = plt.subplots()
figure = plt.Figure()
matplotlib.pyplot.Figure()を作成
# figure = plt.Figure(figsize=(10, 3), dpi=100)
canvas = FigureCanvasTkAgg(figure, master = right_frame) tkinter.Canvasに変換
canvas.get_tk_widget().pack(side = 'bottom', expand = 1) canvasをtkiner.widget()に配置
canvas._tkcanvas.pack(side = 'bottom', expand = 1)
canvasをtkcanvasに配置(理由は不明)
obj['figure'] = figure
obj['canvas'] = canvas
# Ini path frame
inipath_frame = ttk.Frame(left_frame)
inipath_label = ttk.Label(inipath_frame, text = 'Ini file path:', padding = (5,2))
inipath_label.pack(side = 'left')
inipath_entry = ttk.Entry(
inipath_frame,
textvariable = obj['inipath'],
width = 30
)
inipath_entry.pack(side = 'left', expand = True)
inipath_button = ttk.Button(inipath_frame, text = 'path',
command = lambda: inipath_button_click(obj))
inipath_button.pack(side = 'left')
inipath_frame.pack(side = 'top', anchor = 'w')
# Data path frame
datapath_frame = ttk.Frame(left_frame)
datapath_label = ttk.Label(datapath_frame, text = 'Data file path:', padding = (5,2))
datapath_label.pack(side = 'left')
datapath_entry = ttk.Entry(
datapath_frame,
textvariable = obj['datapath'],
width = 30
)
datapath_entry.pack(side = 'left', expand = True)
datapath_button = ttk.Button(datapath_frame, text = 'path',
command = lambda: path_button_click(obj))
datapath_button.pack(side = 'left')
datapath_frame.pack(side = 'top', anchor = 'w')
# Save path frame
savepath_frame = ttk.Frame(left_frame)
savepath_label = ttk.Label(savepath_frame, text = 'Save path:', padding = (5,2))
savepath_label.pack(side = 'left')
savepath_entry = ttk.Entry(
savepath_frame,
textvariable = obj['savepath'],
width = 30
)
savepath_entry.pack(side = 'left', expand = True)
savepath_button = ttk.Button(savepath_frame, text = 'save',
command = lambda: savepath_button_click(obj))
savepath_button.pack(side = 'left')
savepath_frame.pack(side = 'top', anchor = 'w')
# Range frame
range_frame = ttk.Frame(left_frame)
range_label = ttk.Label(range_frame, text = 'x range:', padding = (5,2))
range_label.grid(row = 1, column = 0, sticky = 'w')
x0_entry = ttk.Entry(
range_frame,
textvariable = obj['x0'],
width = 10)
x0_entry.grid(row = 1, column = 1)
range_label2 = ttk.Label(range_frame, text = '-', padding = (5,2))
range_label2.grid(row = 1, column = 2, sticky = E)
x1_entry = ttk.Entry(
range_frame,
textvariable = obj['x1'],
width = 10)
x1_entry.grid(row = 1, column = 3)
range_frame.pack(side = 'top', anchor = 'w')
# Title / XY label frame
xylabel_frame = ttk.Frame(left_frame)
title_label = ttk.Label(xylabel_frame, text = 'Title:')
title_label.grid(row = 0, column = 0, sticky = 'w')
title_entry = ttk.Entry(
xylabel_frame,
textvariable = obj['title'],
width = 50)
title_entry.grid(row = 0, column = 1)
xlabel_label = ttk.Label(xylabel_frame, text = 'x label:')
xlabel_label.grid(row = 1, column = 0, sticky = 'w')
xlabel_entry = ttk.Entry(
xylabel_frame,
textvariable = obj['xlabel'],
width = 50)
xlabel_entry.grid(row = 1, column = 1)
ylabel_label = ttk.Label(xylabel_frame, text = 'y label:')
ylabel_label.grid(row = 2, column = 0, sticky = 'w')
ylabel_entry = ttk.Entry(
xylabel_frame,
textvariable = obj['ylabel'],
width = 50)
ylabel_entry.grid(row = 2, column = 1)
xylabel_frame.pack(side = 'top', anchor = 'w')
# Order frame
order_frame = ttk.Frame(left_frame)
order_label = ttk.Label(order_frame, text = 'fit order:', padding = (5,2))
order_label.pack(side = 'left')
order_entry = ttk.Entry(
order_frame,
textvariable = obj['fit_order'],
width = 10)
order_entry.pack(side = 'top')
order_frame.pack(side = 'top', anchor = 'w')
# Button frame
button_frame = ttk.Frame(left_frame)
lsq_button = ttk.Button(button_frame, text = 'lsq',
command = lambda: lsq_button_click(obj))
lsq_button.pack(side = 'left')
exit_button = ttk.Button(button_frame, text = 'exit', command = lambda: exit())
exit_button.pack(side = 'left')
button_frame.pack(side = 'top', anchor = 'w')
# Font size frame
fontsize_frame = ttk.Frame(left_frame)
fontsize_label = ttk.Label(fontsize_frame, text = 'Font size:')
fontsize_label.pack(side = 'left')
fontsize_entry = ttk.Entry(
fontsize_frame,
textvariable = obj['font_size'],
width = 10)
fontsize_entry.pack(side = 'left')
fontsize_frame.pack(side = 'top', anchor = 'w')
# Output text frame
output_frame = ttk.Frame(left_frame)
output_text = Text(
output_frame,
width = 60,
height = 10)
output_text.pack(side = 'left')
output_frame.pack(side = 'top', anchor = 'w', expand = True)
obj['outputtext'] = output_text
if inifile is not None:
if read_ini(inifile, obj):
# read_csv(datafile, obj)
pass
if datafile is not None:
read_csv(datafile, obj)
root.mainloop()
if __name__ == '__main__':
main()