python使用tkinter库实现自定义的词云图和top10词频统计

这是介绍tkinter库实现桌面应用程序开发的第三篇博文,坚持不易,且行且珍惜。希望我的分享,能帮助大家少走弯路,提高学习效率。

这篇博文,我打算和大家分享一下当前比较火的额词云效果以及实现top10的统计功能,通过良好的、友善的可视化界面能提高感知和实用度,因此我这里继续使用tkinter库作为前端的展示开发库,在这里,我将使用ttk的Progressbar实现在统计过程中的等待交互窗口、使用notebook进行分TAB页显示,使用treeview实现词频统计的列表展现,然后使用LABEL加载词云图,也使用toplevel实现子窗口展现。因此,这篇博文还是非常值得大家花点时间参观一下的。

整体内容大致包括:

1、使用jieba库进行中文分词和词频统计

2、使用wordcloud库生成词云

3、使用tkinter库进行可视化展现

4、使用多线程技术进行异步监听加载

一、jieba库介绍

Jieba是python比较好用的分词模块,可用于中文句子/词性分割、词性标注、未登录词识别,支持用户词典等功能。能较好实现中文分词,同时支持繁体分词。

jieba.cut()提供了三种分词模式,具体包括如下:

精确模式:试图将句子最精确地切开,适合文本分析;

全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义,存在过度切分的问题;

搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

举例如下:

import jieba
import re # 正则表达式库
text = "Jieba是python比较好用的分词模块,可用于中文句子/词性分割、词性标注、未登录词识别,支持用户词典等功能。能较好实现中文分词,同时支持繁体分词。"
# 文本预处理
# 定义正则表达式匹配模式,将符合模式的字符去除
pattern = re.compile(u'\t|\n|\.|-|:|;|\)|\(|\?|"|、|,|。|/')
text = re.sub(pattern, '', text)
#全模式
seg_list = jieba.cut(text, cut_all = True)
print( "全模式:\n" + '/' .join(seg_list))
# 精确模式
seg_list = jieba.cut(text, cut_all = False)
print('精确模式:\n' + '/' .join(seg_list))
# 搜索引擎模式
seg_list = jieba.cut_for_search(text)
print('搜索引擎模式:\n' + '/'.join(seg_list))

运行结果如下:

全模式:
Jieba/是/python/比较/好/用/的/分词/模块/可用/用于/中文/文句/句子/词性/分割/词性/标注/未/登录/词/识别/别支/支持/用户/词典/等/功能/能/较/好/实现/中文/分词/同时/支持/繁体/分词
精确模式:
Jieba/是/python/比较/好用/的/分词/模块/可/用于/中文/句子/词性/分割/词性/标注/未/登录/词/识别/支持/用户/词典/等/功能/能/较/好/实现/中文/分词/同时/支持/繁体/分词
搜索引擎模式:
Jieba/是/python/比较/好用/的/分词/模块/可/用于/中文/句子/词性/分割/词性/标注/未/登录/词/识别/支持/用户/词典/等/功能/能/较/好/实现/中文/分词/同时/支持/繁体/分词

大家可以根据具体实际的需要进行自行选择使用哪种模式。

实现词频统计的具体脚本如下:

import jieba
import collections
import re # 正则表达式库
fn = open('zyds.txt', encoding="utf-8") # 打开文件
text = fn.read() # 读出整个文件
print(text)
fn.close() # 关闭文件
# 文本预处理
# 定义正则表达式匹配模式,将符合模式的字符去除
pattern = re.compile(u'\t|\n|\.|-|:|;|\)|\(|\?|"|、|,|。| |”|“|;')
text = re.sub(pattern, '', text)
#进行词频统计
text_list = jieba.cut(text, cut_all=False)
# 词频TOP10高频统计
word_counts = collections.Counter(text_list) # 对分词做词频统计
word_counts_top10 = word_counts.most_common(10) # 获取前10最高频的词
print (word_counts_top10) # 输出检查

备注:其中文件名可以根据自己实际文件路径和名称进行修改。

在上述脚本的输出结果中,也许大家会发现有很多语气词、或者非关键词被提取出来,因此在这个环节我们可以通过设置stop_words进行关键词过滤和优化。实现逻辑为:新定义一个列表,然后进行过滤,过滤完毕之后的词append到新的列表中去。相关脚本如下:

定义去除词典
stop_words = [u'的', u',',u'和', u'是', u'随着', u'对于',u'对',u'等',u'能',u'都',u'。',
u' ',u'、',u'中',u'在',u'了',u'通常',u'如果',u'我们',u'需要'] # 自定义去除词库

new_text_list=[]
for word in text_list: # 循环读出每个分词
    if word not in stop_words: # 如果不在去除词库中
        new_text_list.append(word) # 分词追加到列表

二、使用wordcloud库生成词云图

wordcloud库通常和jieba结合使用,将分好的单词以图片的方式展示出来,根据单词出现的次数使单词突出。

wordcloud库是python非常优秀的词云展示第三方库。词云以词语为基本单位更加直观和艺术的展示文本, wordcloud把词云当作一个对象,它可以将文本中词语出现的频率作为一个参数绘制词云,而词云的大小、颜色、形状等都是可以设定的。

from wordcloud import WordCloud
from PIL import Image # 图像处理库
import numpy as np # numpy数据处理库
mask = np.array(Image.open('timg1.jpg')) # 定义词频背景
# mask = ImageColorGenerator(back_img)
w_cloud = WordCloud(
    font_path="c:\windows\Fonts\simhei.ttf",
    background_color='white',
    width=1000,
    height=600,
    mask=mask).generate_from_frequencies(text_list)
# 输出成图片:
w_cloud.to_file('wordcloud.jpg')

图片输出结果如下:

这里简要讲下几个会影响图像清晰问题的WordCloud的参数:

mask:遮罩图,字的大小布局和颜色都会依据遮罩图生成。

background_color:背景色,默认黑。根据说明文档,如果想设置透明底色的云词图,那么可以设置background_color=None, mode="RGBA" 生成云词图。

max_font_size:最大字号。

min_font_size:最小字号。不设置的情况下,默认是4。

scale:根据说明文档,当云词图很大的,加大该值会比使用更大的图更快,但值越高也会越慢(计算更复杂)。默认值是1。

random_state:不同的值会让字图的分布不一样。

三、使用tkinter库进行可视化展现

先看看效果图:

有两块内容分别进行处理:

先说第一块:需要实现选择文件功能,其中选择文件分别包括:词频统计的文本文件、背景图文件和需要保存的词云图。

1、实现打开文件对话框,并针对异常报错。

from tkinter import messagebox as msgbox

def load_src_file(*args):
    localfile = filedialog.askopenfile(title='打开单个文件',
                filetypes=[("文本文件","*.txt")],# 只处理的文件类型
                initialdir='D:/')
    if(localfile):
        openfile.delete(0,END)
        openfile.insert(END,localfile.name)
    else:
        msgbox.showinfo(message=('读取文件异常'))

def load_src_file1(*args):
    localfile = filedialog.askopenfile(title='打开单个文件',
                filetypes=[("图片文件", "*.jpg"), ('图片文件', '*.png')],# 只处理的文件类型
                initialdir='D:/')
    if(localfile):
        openfile2.delete(0,END)
        openfile2.insert(END,localfile.name)
    else:
        msgbox.showinfo(message=('读取文件异常'))

def save_out_file(*args):
    localfile = filedialog.asksaveasfile(title='保存文件',
                             filetypes=[("图片文件", "*.jpg"), ('图片文件', '*.png')],  # 只处理的文件类型
                             initialdir='D:/')
    if(localfile):
        savefile.delete(0,END)
        savefile.insert(END,localfile.name)
    else:
        msgbox.showinfo(message=('读取文件异常'))

2、使用treeview控件显示词云图:

(1)设置表格:

col = [1, 2]
tree = ttk.Treeview(tab2, columns=col, height=10, show="headings")
tree.column('0', width=150, anchor='center')  # 指定第一列的宽度和名称, 如果show = "headings", 这一列就被隐藏。
tree.column('1', width=100, anchor='center')
tree.column('2', width=100, anchor='w')
tree.heading('0', text='column0')
tree.heading('1', text='关键词')
tree.heading('2', text='出现次数')

(2)清空表格

def add_tree(self,list, tree):
    #新增数据到表格
    i = 0
    for subList in list:
        tree.insert('', 'end', values=subList)
        i = i + 1

(3)添加表格数据

def add_tree(self,list, tree):
    #新增数据到表格
    i = 0
    for subList in list:
        tree.insert('', 'end', values=subList)
        i = i + 1

举例如下:

from tkinter import *
import tkinter.ttk as ttk

win = Tk()
win.title("Treeview")

col = [1, 2]
data = {"item0": ["1a", "2a"],"item2": ["1c", "2c"]}
tree = ttk.Treeview(win, columns=col, height=10, show="headings")
tree.column('0', width=150, anchor='center')  # 指定第一列的宽度和名称, 如果show = "headings", 这一列就被隐藏。
tree.column('1', width=100, anchor='center')
tree.column('2', width=100, anchor='w')
tree.heading('0', text='column0')
tree.heading('1', text='关键词')
tree.heading('2', text='出现次数')
tree.insert('', 'end', values=data["item0"])
tree.insert('', 'end', values=data["item2"])
tree.pack(expand=Y,fill=BOTH)
win.mainloop()

运行效果如下:

3、Progressbar的实现

from tkinter import *
from tkinter import filedialog, ttk
root = Tk()  # 创建一个Tkinter.Tk()实例
root.title('消息')
root.geometry('600x300+450+200')
def up(i):
        mpb["value"] = i%20
        i+=1
        root.after(100, up,i)  # 每隔1s调用函数up更新控件信息
Label(root, text='正在处理中,请稍候...', fg='red').pack()
mpb = ttk.Progressbar(root, orient="horizontal", length=200, mode="indeterminate")
mpb.pack()
mpb["maximum"] = 20
mpb["value"] = 0
up(0)
root.mainloop()

输出效果如下:

四、使用多线程技术进行异步监听加载

这个部分将会在多线程的文章中进行讲解,敬请期待。

相关代码如下:(暂不包含多线程的相关代码)

from tkinter import *
from tkinter import filedialog
from tkinter import ttk
from PIL import Image,ImageTk
import cv2
import base_final
import time
from tkinter import messagebox as msgbox

def center_window( root, w, h):
    # 获取屏幕 宽、高
    ws = root.winfo_screenwidth()
    hs = root.winfo_screenheight()
    # 计算 x, y 位置
    x = (ws / 2) - (w / 2)
    y = (hs / 2) - (h / 2)
    root.geometry('%dx%d+%d+%d' % (w, h, x, y))

def load_src_file(*args):
    localfile = filedialog.askopenfile(title='打开单个文件',
                filetypes=[("文本文件","*.txt")],# 只处理的文件类型
                initialdir='D:/')
    if(localfile):
        openfile.delete(0,END)
        openfile.insert(END,localfile.name)
    else:
        msgbox.showinfo(message=('读取文件异常'))

def load_src_file1(*args):
    localfile = filedialog.askopenfile(title='打开单个文件',
                filetypes=[("图片文件", "*.jpg"), ('图片文件', '*.png')],# 只处理的文件类型
                initialdir='D:/')
    if(localfile):
        openfile2.delete(0,END)
        openfile2.insert(END,localfile.name)
    else:
        msgbox.showinfo(message=('读取文件异常'))

def save_out_file(*args):
    localfile = filedialog.asksaveasfile(title='保存文件',
                             filetypes=[("图片文件", "*.jpg"), ('图片文件', '*.png')],  # 只处理的文件类型
                             initialdir='D:/')
    if(localfile):
        savefile.delete(0,END)
        savefile.insert(END,localfile.name)
    else:
        msgbox.showinfo(message=('读取文件异常'))

def onclick(*args):
    global data
    source_file = openfile.get()
    result_file = savefile.get()
    source_image = openfile2.get()

    top_level = Toplevel(root)
    top_level.geometry('200x50')
    top_level.title('Sign up window')
    Label(top_level, text='正在处理中,请稍候...', fg='blue',font=("微软雅黑",15)).pack()
    mpb = ttk.Progressbar(top_level, orient="horizontal",length=200, mode="indeterminate")
    mpb.pack()
    mpb["maximum"] = 20
    mpb["value"] = 0
    top_level.overrideredirect(1)  # 去除窗口边框
    top_level.wm_attributes("-alpha", 0.9)  # 透明度(0.0~1.0)
    top_level.wm_attributes("-toolwindow", True)  # 置为工具窗口(没有最大最小按钮)
    top_level.wm_attributes("-topmost", True)  # 永远处于顶层
    center_window(top_level, 200, 150)
    top_level.update()

    def up(i):
        flag = base_1.get_flag()
        while flag:
            mpb["value"] = (i + 1) % 20
            i += 1
            flag = base_1.get_flag()
            top_level.update()
            time.sleep(0.1)
        data = base_1.get_result()
        top_level.destroy()
        return data

    base_1 = base_final.base_run(source_file, source_image,result_file)
    base_1.setDaemon(True)  # 设置守护进程,主线程结束时,不管子线程有没有结束都会退出进程
    base_1.start()
    data = up(0)


    img = cv2.imread(result_file)
    cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    current_image = Image.fromarray(cv2image)  # 将图像转换成Image对象
    pil_image_resized = resize(430, 500, current_image)  # 等比例缩放本地图片
    # imgtk = ImageTk.PhotoImage(word_cloud)
    imgtk = ImageTk.PhotoImage(pil_image_resized)
    label1.imgtk = imgtk
    label1.config(image=imgtk)

    for i in data:
        tree.insert('', 'end', values=[i[0],i[1]])

def resize(w_box, h_box, pil_image):
    f1 = 1.0 * w_box / pil_image.size[0]  # 1.0 forces float division in Python2
    f2 = 1.0 * h_box / pil_image.size[1]
    factor = min([f1, f2])
    width = int(pil_image.size[0] * factor)
    height = int(pil_image.size[1] * factor)
    return pil_image.resize((width, height), Image.ANTIALIAS)

root=Tk()
root.title('词频统计小工具V1.0版')
center_window(root,420,500)
#初始化操作区控件
top_frame = ttk.LabelFrame(root,text='操作区')
open_button = Button(top_frame, text='请选择打开文件',command=load_src_file)
open_button.grid(row=0, sticky="w")
openfile = ttk.Entry(top_frame,
            width=30,
            font=('StSong',14),
            foreground='green')
openfile.insert(END,'./zyds.txt')
openfile.grid(row=0, column=1)

open_button2 = Button(top_frame, text='请选择打开文件', command=load_src_file1)
open_button2.grid(row=1, sticky="w")
openfile2 = ttk.Entry(top_frame,
                     width=30,
                     font=('StSong', 14),
                     foreground='green')
openfile2.insert(END, './timg1.jpg')
openfile2.grid(row=1, column=1)

save_button = Button(top_frame, text='请选择保存文件',command=save_out_file)
save_button.grid(row=2, sticky="w")
savefile = ttk.Entry(top_frame,
            width=30,
            font=('StSong',14),
            foreground='green')
savefile.insert(END,'./out.jpg')
savefile.grid(row=2, column=1)

login = Button(top_frame,text='提交\n处理',command=onclick)
login.grid(row=0, column=2, rowspan=3, padx=5, pady=5)
top_frame.pack(side='top')

#初始化图像显示控件
tabControl = ttk.Notebook(root)  # Create Tab Control
tab1 = ttk.Frame(tabControl)  # Create a tab
label1=Label(tab1,text='欢迎使用词频统计小工具V1.0版!')
label1.pack()
tabControl.add(tab1, text='词云图')  # Add the tab
tab2 = ttk.Frame(tabControl)  # Add a second tab
tabControl.add(tab2, text='top10词频统计')  # Make second tab visible

col = [1, 2]
tree = ttk.Treeview(tab2, columns=col, height=10, show="headings")
tree.column('0', width=150, anchor='center')  # 指定第一列的宽度和名称, 如果show = "headings", 这一列就被隐藏。
tree.column('1', width=100, anchor='center')
tree.column('2', width=100, anchor='w')
tree.heading('0', text='column0')
tree.heading('1', text='关键词')
tree.heading('2', text='出现次数')

vbar = ttk.Scrollbar(tree, command=tree.yview)
tree.configure(yscrollcommand=vbar.set)
vbar.pack(side=RIGHT, fill=Y)

tree.pack(expand=Y,fill=BOTH)
ll = Label(tab2,text='欢迎使用词频统计小工具V1.0版!')
ll.pack(side='left')
tabControl.pack(expand=Y,fill=BOTH)
root.mainloop()

最后出来的效果如下:

发布了15 篇原创文章 · 获赞 16 · 访问量 448

猜你喜欢

转载自blog.csdn.net/dhjabc_1/article/details/105387870
今日推荐