LongLong's Blog

分享IT技术,分享生活感悟,热爱摄影,热爱航天。

使用Python构建图形界面

自从习惯了Web程序后,自己的PC图形界面程序开发基本还停留在Java上,使用Netbeans的图形界面构建工具搭配Swing实现图形界面程序的构建,并且一直感觉Java的图形界面编程的逻辑是非常清晰的——各种操作行为对应相应的Action类或是Listener接口。

之后也尝试过Qt或是其他的图形界面库,感觉都不是特别好用。如今已经好多年不用Java,而且Java目前的生态环境相比现在Python的流行也要差很多了,估计主要还是用在Android开发和比较老的电商系统上了吧。

目前的需求是借助Python的Numpy和Matplotlib实现一些类型Matlab的功能,并且要封装成为一个可执行文件。

1. Tk图形界面库

Tkinter 模块(Tk 接口)是Python的标准Tk GUI工具包的接口 .Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows 和macOS系统里。Tk8.0的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。

其最大的优点就是作为了Python的常用标准库,直接就可以使用,而且使用上也相对简单,对于开发较为简单的图形界面程序比较友好,使用难度也相对较低。其运行的核心代码如下

import tkinter;

if __name__ == '__main__':
    tk = tkinter.Tk(className='Main');
    tk.mainloop();

2. Tk控件

Tkinter的提供各种控件,如按钮,标签和文本框等共计15种。在使用时需要关联到控件的上层控件,实现整个控件的树形结构。如下面的代码实现了一个完整的菜单控件。控件使用add_command方法实现绑定操作时执行的代码。

menu = tkinter.Menu(tk);
m1 = tkinter.Menu(menu, tearoff=False);
m1.add_command(label='打开', command=load_data);
m1.add_command(label='保存', command=save_data);
m1.add_command(label='退出', command=on_exit);
menu.add_cascade(label='文件', menu=m1);
tk.config(menu=menu);

除了基本控件,Tkinter还提供了一些常用的组合控件,如各种类型的提示框,实现消息提示,文件选择等功能。

#提示信息
tkinter.messagebox.showerror('警告', '数据格式错误!');
#选择要打开的文件
path = tkinter.filedialog.askopenfilename();

3. 界面布局

Tkinter控件有特定的几何状态管理方法,管理整个控件区域组织,以下是Tkinter公开的几何管理类:包、网格、位置。比较类似Java中的Layout。使用包(pack)可是实现控件大方位的指定(上下左右)。

#放置在顶部
canvas.get_tk_widget().pack(side=tkinter.TOP);
#放置在底部
s2.pack(side=tkinter.BOTTOM);

4. 动态调整控件属性

在图形界面程序中经常需要进行一定操作后,根据执行的结果动态调整某些控件的某些属性,Tk中则是通过控件的config方法,该方法接受一个Python字典结构,字典中的键值为需要调整的属性,值则为调整后的属性值。如以下代码将两个范围控件的最大值进行更新。

fm = data.maxFreq() + 2;
s1.config({'to' : fm});
s2.config({'to' : fm});

5. 在Tk中集成Matplotlib图表

由于需要使用Matplotlib绘制图表,并继承在图形界面中,Tk也支持将Matplotlib图表放置在界面中,可通过以下方法实现

#创建一个Matplotlib绘图
figure = matplotlib.figure.Figure();
#利用绘图创建一个画布
canvas = matplotlib.backends.backend_tkagg.FigureCanvasTkAgg(figure, master=tk);
#将画布放置到界面中
canvas.get_tk_widget().pack(side=tkinter.TOP);
#在完成绘图后调用更新显示
canvas.draw();

6. 打包程序

如今Python可以借助pyinstaller实现对源代码进行打包,形成一个可执行文件,如此就可以实现程序的分发,而不需要运行的计算机安装配置对应的Python环境,同时也能一定程度上隐藏源代码。打包的命令格式如下

pyinstaller -F -w -i <程序图标文件> [源代码文件]

其中-F表示生成一个exe文件,-w表示运行时不弹出命令提示符窗口,-i可以指定可执行文件的图标。

使用PyTorch进行数据拟合

对于较为复杂的曲线进行拟合,除了传统的使用多项式、分段线性等拟合方式,使用神经网络进行拟合也称为越来越流行的一种方法,特别是输入变量为多维,并且在拟合数据样本量较大的情况,使用神经网络会让拟合的过程更为简单。

目前最主流的神经网络框架已经由Tensorflow转向了PyTorch,相比Tensorflow,PyTorch更为轻量化,其类似Numpy提供了多维数组(张量)的相关操作,并提供了一套基于自动微分的优化框架,而训练神经网络的过程本质上也是一个优化问题,相对其他框架提供了更为通用的功能,同时目前Keras也提供了PyTorch的版本,进行代码的迁移应该也会比较简单。

1. 拟合基本流程

使用PyTorch进行拟合的流程与使用Keras非常类似,只是优化过程的循环需要自行编写,其主要代码如下:

model = torch.nn.Sequential();
#创建第一层网络和激活函数,网络的输入为模型输入参数的维度
model.append(torch.nn.Linear(6, 200));
model.append(torch.nn.Sigmoid());
#创建第二层网络和激活函数
model.append(torch.nn.Linear(200, 200));
model.append(torch.nn.ReLU());
#创建第三层网络和激活函数,网络的输出为模型输出参数的维度
model.append(torch.nn.Linear(200, 1));
model.append(torch.nn.ReLU());

#设置训练模型的优化器和损失函数
optimizer = torch.optim.Adam(model.paramenters(), lr=learn_rate);
loss_fn = torch.nn.MSELoss();

for i in range(0, epoch):
    #进行预测,并计算误差
    y_p = model(x);
    loss = loss_fn(y_p, y);
    #计算梯度,并进行优化
    optimizer.zero_grad();
    loss.backward();
    optimizer.step();

可见除了需要给出神经网络的构造外,其余过程和一般的优化问题是完全一样的。

2. 预测基本流程

预测的过程和训练中调用模型进行预测是完全一样的,但需要注意传入的参数应该与训练时的使用的结构完全相同的tensor,PyTorch和Keras一样可以保存训练好的模型,并从文件中读取模型以便直接使用,其主要代码如下:

model = torch.load('Model.pt');
y = model(x);

需要注意的是无论模型返回的结果有几个维度,返回值都将是一个tensor,为此在使用的时候需要进行相关的转换,特别是返回结果是一个值的时候。

3. Python读写Excel表格

在进行模型训练时可能会遇到训练集是Excel文件的情况,同时也会遇到需要将预测的结果回写到Excel文件的情况,目前大多数Python的Excel库都支持能支持从Excel文件中读取数据,经过测试读写操作均比较好用的是xlwinds,但xlwinds要求必须在Windows环境并且安装了Excel的情况下使用,其工作流程就是调用了Excel API直接进行文件的操作,特别是在将visible设为True时,甚至可以看到Excel文件的操作过程。

其读写操作的代码如下:

app = xw.App(visibl=True, add_book=False);
#打开一个已经存在的Excel文件
book app.books.open('Data.xlsx');
#获取第一个表格
sheet = book.sheets[0];
#获取表格B2及其右下方区域的全部数据
data = sheet.range('B2').expand().value;

#更新i行,j列的数据
sheet[i, j].value = c;
#对结果进行另存为,并关闭文件
book.save('Data-New.xlsx');
book.close();

4. 拟合实例

对于一电池的电量进行随使用次数及每次的充放电时间进行拟合,其拟合结果曲线如所示:

可见拟合效果还是不错的,并且在数据有较强的波动的情况下也并不存在明显的过拟合现象。