Python中tkinter库图形可视化工具详解:涵盖15种图形的完整代码实现
前文,我们开发了一个基于Python的tkinter库的图形可视化工具,其中包括了饼图、柱状图、折线图、散点图、直方图5 种图形,然而日常中,常用的图形还有很多,接下来,我们在原有基础上进行升级,继续增加10种常用的图形。
上一版本:基于Python的tkinter库开发的一个图形可视化工具(完整代码)-CSDN博客
一、程序结构说明
为了更好的方便用户,之后基于现有代码进行个性化的增加内容,有必要先了解本程序的基本结构。
(一)程序文件结构
本程序采用单文件结构,所有代码集中在一个 Python 文件中:
graph_visualizer.py
(二)基本类及其功能
程序的核心是 GraphVisualizerApp 类,负责管理整个图形可视化工具的界面和功能:
root:主窗口对象current_graph_type:当前选中的图形类型figure 和 canvas:matplotlib 图形和画布对象pie_labels, bar_values 等)__init__:初始化应用程序,设置 UI 布局和默认图形create_menu:创建菜单栏,包含各种图形类型选项setup_layout:设置界面布局,分为参数设置区和图形显示区clear_param_frame:清除参数设置区的所有控件generate_graph:根据当前图形类型和参数生成图形reset_params:重置当前图形的参数为默认值show_about:显示关于对话框GraphVisualizerApp
├── __init__(self, root)
│ ├── 创建菜单栏
│ ├── 设置界面布局
│ └── 初始化默认图形
│
├── create_menu(self)
│ ├── 创建"图形类型"下拉菜单
│ │ ├── 饼图
│ │ ├── 柱状图
│ │ ├── 折线图
│ │ ├── 散点图
│ │ ├── 直方图
│ │ ├── 箱线图
│ │ ├── 热力图
│ │ ├── 雷达图
│ │ ├── 气泡图
│ │ ├── 面积图
│ │ ├── 堆叠柱状图
│ │ ├── 散点矩阵图
│ │ ├── 词云图
│ │ ├── 瀑布图
│ │ └── 旭日图
│ ├── 添加"关于"和"退出"选项
│ └── 设置菜单栏
│
├── setup_layout(self)
│ ├── 创建左右框架
│ ├── 设置参数设置区域
│ ├── 设置图形显示区域
│ └── 创建按钮区域
│
├── clear_param_frame(self)
│ └── 清除参数区域所有控件
│
├── 图形设置函数
│ ├── show_pie_chart(self)
│ ├── show_bar_chart(self)
│ ├── show_line_chart(self)
│ ├── show_scatter_chart(self)
│ ├── show_histogram(self)
│ ├── show_boxplot(self)
│ ├── show_heatmap(self)
│ ├── show_radar_chart(self)
│ ├── show_bubble_chart(self)
│ ├── show_area_chart(self)
│ ├── show_stacked_bar(self)
│ ├── show_scatter_matrix(self)
│ ├── show_wordcloud(self)
│ ├── show_waterfall(self)
│ └── show_sunburst(self)
│
├── generate_graph(self)
│ ├── 根据当前图形类型生成图形
│ │ ├── 饼图
│ │ ├── 柱状图
│ │ ├── 折线图
│ │ ├── 散点图
│ │ ├── 直方图
│ │ ├── 箱线图
│ │ ├── 热力图
│ │ ├── 雷达图
│ │ ├── 气泡图
│ │ ├── 面积图
│ │ ├── 堆叠柱状图
│ │ ├── 散点矩阵图
│ │ ├── 词云图
│ │ ├── 瀑布图
│ │ └── 旭日图
│ ├── 调整布局
│ └── 绘制图形
│
├── reset_params(self)
│ ├── 根据当前图形类型重置参数
│ │ ├── 饼图
│ │ ├── 柱状图
│ │ ├── 折线图
│ │ ├── 散点图
│ │ ├── 直方图
│ │ ├── 箱线图
│ │ ├── 热力图
│ │ ├── 雷达图
│ │ ├── 气泡图
│ │ ├── 面积图
│ │ ├── 堆叠柱状图
│ │ ├── 散点矩阵图
│ │ ├── 词云图
│ │ ├── 瀑布图
│ │ └── 旭日图
│ └── 重新生成图形
│
└── show_about(self)
└── 显示关于对话框
(三)核心函数及其作用
1. 界面初始化函数
create_menu():
setup_layout():
2. 图形参数设置函数
show_pie_chart()、show_bar_chart() 等:
3. 图形生成函数
generate_graph():
4. 辅助功能函数
reset_params():
show_about():
(四)程序工作流程
- 初始化:创建主窗口,设置 UI 布局,默认显示饼图界面
- 用户交互:
- 通过菜单栏选择图形类型
- 在参数设置区修改图形参数
- 点击 "生成图形" 按钮更新显示
- 点击 "重置参数" 按钮恢复默认值
- 图形生成:
- 根据当前图形类型,获取对应参数
- 使用 matplotlib 绘制图形
- 在右侧区域显示生成的图形
(五)扩展说明
-
图形类型:程序支持 15 种图形类型,包括:
- 基础图形:饼图、柱状图、折线图、散点图、直方图
- 高级图形:箱线图、热力图、雷达图、气泡图、面积图
- 统计图形:堆叠柱状图、散点矩阵图
- 文本可视化:词云图
- 层次结构:瀑布图、旭日图
-
代码结构:
- 每种图形的参数设置和绘制逻辑集中在对应的函数中
- 使用
current_graph_type变量跟踪当前选中的图形类型 - 参数重置逻辑按图形类型分类在
reset_params()函数中 -
依赖管理:
- 基础依赖:tkinter、matplotlib、numpy
- 高级图形依赖:pandas、wordcloud、plotly
- 中文显示设置:通过 matplotlib 字体配置支持中文
(六)需要改动的地方
基于以上说明,我们就清楚了,接下来新增的图形,主要是要改动:
(1)create_menu(self)函数中增加菜单
(2)GraphVisualizerApp类下添加方法:
│ ├── show_boxplot(self)
│ ├── show_heatmap(self)
│ ├── show_radar_chart(self)
│ ├── show_bubble_chart(self)
│ ├── show_area_chart(self)
│ ├── show_stacked_bar(self)
│ ├── show_scatter_matrix(self)
│ ├── show_wordcloud(self)
│ ├── show_waterfall(self)
│ └── show_sunburst(self)
(3)generate_graph(self)函数中,根据当前选择的图形类型生成图形
(4)reset_params(self)函数中,重置当前图形的参数。
就修改4个地方。
以下是基于前文内容基础上扩展的 10 种常用图形生成功能的详细说明和代码实现。
二、 新增图形功能概述
在原有 5 种图形(饼图、柱状图、折线图、散点图、直方图)的基础上,新增以下 10 种常用图形类型:
- 箱线图(Box Plot)
- 热力图(Heatmap)
- 雷达图(Radar Chart)
- 气泡图(Bubble Chart)
- 面积图(Area Chart)
- 堆叠柱状图(Stacked Bar Chart)
- 散点矩阵图(Scatter Matrix)
- 词云图(Word Cloud)
- 瀑布图(Waterfall Chart)
- 旭日图(Sunburst Chart)
(一) 箱线图(Box Plot)
箱线图用于显示数据的分布情况,包括中位数、四分位数和异常值。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_boxplot(self):
self.current_graph_type = "boxplot"
self.clear_param_frame()
self.root.title("图形可视化工具 - 箱线图")
ttk.Label(self.param_frame, text="数据集(多组用分号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.boxplot_data = ttk.Entry(self.param_frame, width=30)
self.boxplot_data.insert(0, "1,2,3,4,5,6,7;5,6,7,8,9,10,11;2,3,4,5,6,7,8")
self.boxplot_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="标签(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.boxplot_labels = ttk.Entry(self.param_frame, width=30)
self.boxplot_labels.insert(0, "数据组A,数据组B,数据组C")
self.boxplot_labels.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.boxplot_title = ttk.Entry(self.param_frame, width=30)
self.boxplot_title.insert(0, "箱线图示例")
self.boxplot_title.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="是否显示异常值:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.boxplot_showfliers = tk.BooleanVar(value=True)
ttk.Checkbutton(self.param_frame, variable=self.boxplot_showfliers).grid(row=3, column=1, sticky=tk.W, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "boxplot":
# 箱线图
data_sets = self.boxplot_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
labels = self.boxplot_labels.get().split(',')
title = self.boxplot_title.get()
showfliers = self.boxplot_showfliers.get()
ax = self.figure.add_subplot(111)
ax.boxplot(data, labels=labels, showfliers=showfliers)
ax.set_title(title)
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "boxplot":
self.boxplot_data.delete(0, tk.END)
self.boxplot_data.insert(0, "1,2,3,4,5,6,7;5,6,7,8,9,10,11;2,3,4,5,6,7,8")
self.boxplot_labels.delete(0, tk.END)
self.boxplot_labels.insert(0, "数据组A,数据组B,数据组C")
self.boxplot_title.delete(0, tk.END)
self.boxplot_title.insert(0, "箱线图示例")
self.boxplot_showfliers.set(True)
(二) 热力图(Heatmap)
热力图用颜色梯度表示矩阵数据。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_heatmap(self):
self.current_graph_type = "heatmap"
self.clear_param_frame()
self.root.title("图形可视化工具 - 热力图")
ttk.Label(self.param_frame, text="数据(用逗号分隔行,分号分隔列):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.heatmap_data = ttk.Entry(self.param_frame, width=30)
self.heatmap_data.insert(0, "1,2,3;4,5,6;7,8,9")
self.heatmap_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="行标签(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.heatmap_row_labels = ttk.Entry(self.param_frame, width=30)
self.heatmap_row_labels.insert(0, "A,B,C")
self.heatmap_row_labels.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="列标签(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.heatmap_col_labels = ttk.Entry(self.param_frame, width=30)
self.heatmap_col_labels.insert(0, "X,Y,Z")
self.heatmap_col_labels.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.heatmap_title = ttk.Entry(self.param_frame, width=30)
self.heatmap_title.insert(0, "热力图示例")
self.heatmap_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="颜色映射:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.heatmap_cmap = ttk.Combobox(self.param_frame, values=["viridis", "plasma", "inferno", "magma", "cividis"], width=27)
self.heatmap_cmap.current(0)
self.heatmap_cmap.grid(row=4, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "heatmap":
# 热力图
data_str = self.heatmap_data.get().split(';')
data = []
for row in data_str:
data.append([float(x) for x in row.split(',')])
row_labels = self.heatmap_row_labels.get().split(',')
col_labels = self.heatmap_col_labels.get().split(',')
title = self.heatmap_title.get()
cmap = self.heatmap_cmap.get()
ax = self.figure.add_subplot(111)
im = ax.imshow(data, cmap=cmap)
# 设置坐标轴标签
ax.set_xticks(np.arange(len(col_labels)))
ax.set_yticks(np.arange(len(row_labels)))
ax.set_xticklabels(col_labels)
ax.set_yticklabels(row_labels)
# 添加颜色条
self.figure.colorbar(im)
ax.set_title(title)
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "heatmap":
self.heatmap_data.delete(0, tk.END)
self.heatmap_data.insert(0, "1,2,3;4,5,6;7,8,9")
self.heatmap_row_labels.delete(0, tk.END)
self.heatmap_row_labels.insert(0, "A,B,C")
self.heatmap_col_labels.delete(0, tk.END)
self.heatmap_col_labels.insert(0, "X,Y,Z")
self.heatmap_title.delete(0, tk.END)
self.heatmap_title.insert(0, "热力图示例")
self.heatmap_cmap.current(0)
(三) 雷达图(Radar Chart)
雷达图用于比较多个定量变量。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_radar_chart(self):
self.current_graph_type = "radar"
self.clear_param_frame()
self.root.title("图形可视化工具 - 雷达图")
ttk.Label(self.param_frame, text="指标名称(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.radar_labels = ttk.Entry(self.param_frame, width=30)
self.radar_labels.insert(0, "速度,力量,耐力,敏捷,智力,防御")
self.radar_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组(多组用分号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.radar_data = ttk.Entry(self.param_frame, width=30)
self.radar_data.insert(0, "70,80,60,90,50,75;60,90,80,70,65,85")
self.radar_data.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组名称(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.radar_group_names = ttk.Entry(self.param_frame, width=30)
self.radar_group_names.insert(0, "角色A,角色B")
self.radar_group_names.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.radar_title = ttk.Entry(self.param_frame, width=30)
self.radar_title.insert(0, "雷达图示例")
self.radar_title.grid(row=3, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "radar":
# 雷达图
labels = self.radar_labels.get().split(',')
data_sets = self.radar_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
group_names = self.radar_group_names.get().split(',')
title = self.radar_title.get()
# 计算角度
angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False).tolist()
# 闭合雷达图
labels = labels + [labels[0]]
angles = angles + [angles[0]]
ax = self.figure.add_subplot(111, polar=True)
# 绘制每个数据组
for i, d in enumerate(data):
d = d + [d[0]] # 闭合数据
ax.plot(angles, d, 'o-', linewidth=2, label=group_names[i])
ax.fill(angles, d, alpha=0.25)
# 设置标签
ax.set_thetagrids(np.degrees(angles[:-1]), labels[:-1])
ax.set_title(title)
ax.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "radar":
self.radar_labels.delete(0, tk.END)
self.radar_labels.insert(0, "速度,力量,耐力,敏捷,智力,防御")
self.radar_data.delete(0, tk.END)
self.radar_data.insert(0, "70,80,60,90,50,75;60,90,80,70,65,85")
self.radar_group_names.delete(0, tk.END)
self.radar_group_names.insert(0, "角色A,角色B")
self.radar_title.delete(0, tk.END)
self.radar_title.insert(0, "雷达图示例")
(四) 气泡图(Bubble Chart)
气泡图是散点图的扩展,用气泡大小表示第三维数据。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_bubble_chart(self):
self.current_graph_type = "bubble"
self.clear_param_frame()
self.root.title("图形可视化工具 - 气泡图")
ttk.Label(self.param_frame, text="X轴数据(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.bubble_x = ttk.Entry(self.param_frame, width=30)
self.bubble_x.insert(0, "1,2,3,4,5,6,7")
self.bubble_x.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴数据(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.bubble_y = ttk.Entry(self.param_frame, width=30)
self.bubble_y.insert(0, "65,59,80,81,56,55,70")
self.bubble_y.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="气泡大小(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.bubble_size = ttk.Entry(self.param_frame, width=30)
self.bubble_size.insert(0, "100,200,300,400,250,150,350")
self.bubble_size.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.bubble_title = ttk.Entry(self.param_frame, width=30)
self.bubble_title.insert(0, "气泡图示例")
self.bubble_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.bubble_xlabel = ttk.Entry(self.param_frame, width=30)
self.bubble_xlabel.insert(0, "X轴")
self.bubble_xlabel.grid(row=4, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.bubble_ylabel = ttk.Entry(self.param_frame, width=30)
self.bubble_ylabel.insert(0, "Y轴")
self.bubble_ylabel.grid(row=5, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "bubble":
# 气泡图
x = [float(i) for i in self.bubble_x.get().split(',')]
y = [float(i) for i in self.bubble_y.get().split(',')]
size = [float(i) for i in self.bubble_size.get().split(',')]
title = self.bubble_title.get()
xlabel = self.bubble_xlabel.get()
ylabel = self.bubble_ylabel.get()
ax = self.figure.add_subplot(111)
scatter = ax.scatter(x, y, s=size, alpha=0.5)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
# 添加图例
handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6)
legend2 = ax.legend(handles, labels, loc="upper right", title="气泡大小")
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "bubble":
self.bubble_x.delete(0, tk.END)
self.bubble_x.insert(0, "1,2,3,4,5,6,7")
self.bubble_y.delete(0, tk.END)
self.bubble_y.insert(0, "65,59,80,81,56,55,70")
self.bubble_size.delete(0, tk.END)
self.bubble_size.insert(0, "100,200,300,400,250,150,350")
self.bubble_title.delete(0, tk.END)
self.bubble_title.insert(0, "气泡图示例")
self.bubble_xlabel.delete(0, tk.END)
self.bubble_xlabel.insert(0, "X轴")
self.bubble_ylabel.delete(0, tk.END)
self.bubble_ylabel.insert(0, "Y轴")
(五) 面积图(Area Chart)
面积图是折线图的扩展,用填充区域表示数据。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_area_chart(self):
self.current_graph_type = "area"
self.clear_param_frame()
self.root.title("图形可视化工具 - 面积图")
ttk.Label(self.param_frame, text="X轴标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.area_xlabels = ttk.Entry(self.param_frame, width=30)
self.area_xlabels.insert(0, "一月,二月,三月,四月,五月,六月")
self.area_xlabels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组(多组用分号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.area_data = ttk.Entry(self.param_frame, width=30)
self.area_data.insert(0, "3,4,6,8,9,11;2,2,3,5,6,8;1,5,8,9,10,12")
self.area_data.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组名称(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.area_group_names = ttk.Entry(self.param_frame, width=30)
self.area_group_names.insert(0, "产品A,产品B,产品C")
self.area_group_names.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.area_title = ttk.Entry(self.param_frame, width=30)
self.area_title.insert(0, "面积图示例")
self.area_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="是否堆叠:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.area_stacked = tk.BooleanVar(value=True)
ttk.Checkbutton(self.param_frame, variable=self.area_stacked).grid(row=4, column=1, sticky=tk.W, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "area":
# 面积图
xlabels = self.area_xlabels.get().split(',')
data_sets = self.area_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
group_names = self.area_group_names.get().split(',')
title = self.area_title.get()
stacked = self.area_stacked.get()
ax = self.figure.add_subplot(111)
if stacked:
# 堆叠面积图
ax.stackplot(xlabels, data, labels=group_names)
else:
# 非堆叠面积图
for i, d in enumerate(data):
ax.fill_between(xlabels, d, alpha=0.5, label=group_names[i])
ax.set_title(title)
ax.legend(loc='upper left')
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "area":
self.area_xlabels.delete(0, tk.END)
self.area_xlabels.insert(0, "一月,二月,三月,四月,五月,六月")
self.area_data.delete(0, tk.END)
self.area_data.insert(0, "3,4,6,8,9,11;2,2,3,5,6,8;1,5,8,9,10,12")
self.area_group_names.delete(0, tk.END)
self.area_group_names.insert(0, "产品A,产品B,产品C")
self.area_title.delete(0, tk.END)
self.area_title.insert(0, "面积图示例")
self.area_stacked.set(True)
(六) 堆叠柱状图(Stacked Bar Chart)
堆叠柱状图用于显示多个数据系列的累积效果。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_stacked_bar(self):
self.current_graph_type = "stacked_bar"
self.clear_param_frame()
self.root.title("图形可视化工具 - 堆叠柱状图")
ttk.Label(self.param_frame, text="X轴标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.stacked_xlabels = ttk.Entry(self.param_frame, width=30)
self.stacked_xlabels.insert(0, "一月,二月,三月,四月,五月")
self.stacked_xlabels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组(多组用分号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.stacked_data = ttk.Entry(self.param_frame, width=30)
self.stacked_data.insert(0, "10,15,20,17,22;15,12,19,21,25;5,7,11,9,13")
self.stacked_data.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组名称(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.stacked_group_names = ttk.Entry(self.param_frame, width=30)
self.stacked_group_names.insert(0, "组A,组B,组C")
self.stacked_group_names.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.stacked_title = ttk.Entry(self.param_frame, width=30)
self.stacked_title.insert(0, "堆叠柱状图示例")
self.stacked_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.stacked_xlabel = ttk.Entry(self.param_frame, width=30)
self.stacked_xlabel.insert(0, "月份")
self.stacked_xlabel.grid(row=4, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.stacked_ylabel = ttk.Entry(self.param_frame, width=30)
self.stacked_ylabel.insert(0, "数值")
self.stacked_ylabel.grid(row=5, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "stacked_bar":
# 堆叠柱状图
xlabels = self.stacked_xlabels.get().split(',')
data_sets = self.stacked_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
group_names = self.stacked_group_names.get().split(',')
title = self.stacked_title.get()
xlabel = self.stacked_xlabel.get()
ylabel = self.stacked_ylabel.get()
ax = self.figure.add_subplot(111)
x = np.arange(len(xlabels))
width = 0.35
bottom = np.zeros(len(xlabels))
for i, d in enumerate(data):
ax.bar(x, d, width, bottom=bottom, label=group_names[i])
bottom += np.array(d)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.set_xticks(x)
ax.set_xticklabels(xlabels)
ax.legend()
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "stacked_bar":
self.stacked_xlabels.delete(0, tk.END)
self.stacked_xlabels.insert(0, "一月,二月,三月,四月,五月")
self.stacked_data.delete(0, tk.END)
self.stacked_data.insert(0, "10,15,20,17,22;15,12,19,21,25;5,7,11,9,13")
self.stacked_group_names.delete(0, tk.END)
self.stacked_group_names.insert(0, "组A,组B,组C")
self.stacked_title.delete(0, tk.END)
self.stacked_title.insert(0, "堆叠柱状图示例")
self.stacked_xlabel.delete(0, tk.END)
self.stacked_xlabel.insert(0, "月份")
self.stacked_ylabel.delete(0, tk.END)
self.stacked_ylabel.insert(0, "数值")
(七) 散点矩阵图(Scatter Matrix)
散点矩阵图用于显示多个变量之间的关系。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_scatter_matrix(self):
self.current_graph_type = "scatter_matrix"
self.clear_param_frame()
self.root.title("图形可视化工具 - 散点矩阵图")
ttk.Label(self.param_frame, text="数据集(多组用分号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.scatter_matrix_data = ttk.Entry(self.param_frame, width=30)
self.scatter_matrix_data.insert(0, "1,2,3,4,5;5,4,3,2,1;2,3,5,4,1")
self.scatter_matrix_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="变量名称(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.scatter_matrix_labels = ttk.Entry(self.param_frame, width=30)
self.scatter_matrix_labels.insert(0, "变量A,变量B,变量C")
self.scatter_matrix_labels.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.scatter_matrix_title = ttk.Entry(self.param_frame, width=30)
self.scatter_matrix_title.insert(0, "散点矩阵图示例")
self.scatter_matrix_title.grid(row=2, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "scatter_matrix":
# 散点矩阵图
data_sets = self.scatter_matrix_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
# 转置数据以匹配pandas DataFrame格式
data = np.array(data).T
labels = self.scatter_matrix_labels.get().split(',')
title = self.scatter_matrix_title.get()
# 使用pandas绘制散点矩阵图
import pandas as pd
df = pd.DataFrame(data, columns=labels)
ax = self.figure.add_subplot(111)
pd.plotting.scatter_matrix(df, alpha=0.8, figsize=(6, 6), diagonal='kde', ax=ax)
self.figure.suptitle(title)
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "scatter_matrix":
self.scatter_matrix_data.delete(0, tk.END)
self.scatter_matrix_data.insert(0, "1,2,3,4,5;5,4,3,2,1;2,3,5,4,1")
self.scatter_matrix_labels.delete(0, tk.END)
self.scatter_matrix_labels.insert(0, "变量A,变量B,变量C")
self.scatter_matrix_title.delete(0, tk.END)
self.scatter_matrix_title.insert(0, "散点矩阵图示例")
(八) 词云图(Word Cloud)
词云图用于展示文本数据中词语的频率分布。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_wordcloud(self):
self.current_graph_type = "wordcloud"
self.clear_param_frame()
self.root.title("图形可视化工具 - 词云图")
ttk.Label(self.param_frame, text="文本内容:").grid(row=0, column=0, sticky=tk.NW, pady=5)
self.wordcloud_text = scrolledtext.ScrolledText(self.param_frame, width=30, height=10)
self.wordcloud_text.insert(tk.END, "Python是一种广泛使用的高级编程语言,特别适合数据科学和机器学习。Python的语法简洁,易于学习,拥有丰富的库和工具。")
self.wordcloud_text.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.wordcloud_title = ttk.Entry(self.param_frame, width=30)
self.wordcloud_title.insert(0, "词云图示例")
self.wordcloud_title.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="最大词数:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.wordcloud_max_words = ttk.Entry(self.param_frame, width=30)
self.wordcloud_max_words.insert(0, "100")
self.wordcloud_max_words.grid(row=2, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "wordcloud":
# 词云图
try:
from wordcloud import WordCloud
except ImportError:
messagebox.showerror("错误", "请先安装wordcloud库: pip install wordcloud")
return
text = self.wordcloud_text.get("1.0", tk.END)
title = self.wordcloud_title.get()
max_words = int(self.wordcloud_max_words.get())
ax = self.figure.add_subplot(111)
# 生成词云
wordcloud = WordCloud(max_words=max_words, background_color="white").generate(text)
ax.imshow(wordcloud, interpolation='bilinear')
ax.axis("off")
ax.set_title(title)
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "wordcloud":
self.wordcloud_text.delete("1.0", tk.END)
self.wordcloud_text.insert(tk.END, "Python是一种广泛使用的高级编程语言,特别适合数据科学和机器学习。Python的语法简洁,易于学习,拥有丰富的库和工具。")
self.wordcloud_title.delete(0, tk.END)
self.wordcloud_title.insert(0, "词云图示例")
self.wordcloud_max_words.delete(0, tk.END)
self.wordcloud_max_words.insert(0, "100")
(九) 瀑布图(Waterfall Chart)
瀑布图用于显示起始值如何通过一系列增加和减少达到最终值。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_waterfall(self):
self.current_graph_type = "waterfall"
self.clear_param_frame()
self.root.title("图形可视化工具 - 瀑布图")
ttk.Label(self.param_frame, text="类别名称(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.waterfall_labels = ttk.Entry(self.param_frame, width=30)
self.waterfall_labels.insert(0, "起始,销售增长,成本增加,新产品,最终")
self.waterfall_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数值(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.waterfall_values = ttk.Entry(self.param_frame, width=30)
self.waterfall_values.insert(0, "1000,500,-300,200,0")
self.waterfall_values.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.waterfall_title = ttk.Entry(self.param_frame, width=30)
self.waterfall_title.insert(0, "瀑布图示例")
self.waterfall_title.grid(row=2, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "waterfall":
# 瀑布图
labels = self.waterfall_labels.get().split(',')
values = [float(x) for x in self.waterfall_values.get().split(',')]
title = self.waterfall_title.get()
# 计算累积值
is_total = [False] * len(values)
is_total[-1] = True # 最后一个是总计
# 创建一个新的DataFrame处理瀑布图数据
import pandas as pd
df = pd.DataFrame({
'label': labels,
'value': values,
'is_total': is_total
})
# 计算绝对数值
abs_values = []
prev = 0
for i, row in df.iterrows():
if row['is_total']:
abs_values.append(row['value'])
else:
abs_values.append(prev + row['value'])
prev = abs_values[-1]
df['abs_value'] = abs_values
ax = self.figure.add_subplot(111)
# 绘制瀑布图
for i, row in df.iterrows():
if row['is_total']:
ax.bar(i, row['abs_value'], color='blue')
elif row['value'] >= 0:
ax.bar(i, row['value'], bottom=row['abs_value']-row['value'], color='green')
else:
ax.bar(i, row['value'], bottom=row['abs_value'], color='red')
ax.set_xticks(range(len(df)))
ax.set_xticklabels(df['label'])
ax.set_title(title)
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "waterfall":
self.waterfall_labels.delete(0, tk.END)
self.waterfall_labels.insert(0, "起始,销售增长,成本增加,新产品,最终")
self.waterfall_values.delete(0, tk.END)
self.waterfall_values.insert(0, "1000,500,-300,200,0")
self.waterfall_title.delete(0, tk.END)
self.waterfall_title.insert(0, "瀑布图示例")
(十) 旭日图(Sunburst Chart)
旭日图用于展示层次数据的占比关系。
1. 参数设置界面
直接在GraphVisualizerApp类下添加新的方法。
def show_sunburst(self):
self.current_graph_type = "sunburst"
self.clear_param_frame()
self.root.title("图形可视化工具 - 旭日图")
ttk.Label(self.param_frame, text="标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.sunburst_labels = ttk.Entry(self.param_frame, width=30)
self.sunburst_labels.insert(0, "A,B,A1,A2,B1,B2;A,A,B,B,B,B")
self.sunburst_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数值(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.sunburst_values = ttk.Entry(self.param_frame, width=30)
self.sunburst_values.insert(0, "10,15,5,5,8,7")
self.sunburst_values.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.sunburst_title = ttk.Entry(self.param_frame, width=30)
self.sunburst_title.insert(0, "旭日图示例")
self.sunburst_title.grid(row=2, column=1, pady=5)
self.generate_graph()
2. 图形生成代码
在generate_graph(self)函数中添加。
elif self.current_graph_type == "sunburst":
# 旭日图
try:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
except ImportError:
messagebox.showerror("错误", "请先安装plotly库: pip install plotly")
return
labels_str, parents_str = self.sunburst_labels.get().split(';')
labels = labels_str.split(',')
parents = parents_str.split(',')
values = [float(x) for x in self.sunburst_values.get().split(',')]
title = self.sunburst_title.get()
# 创建旭日图
fig = make_subplots(rows=1, cols=1, specs=[[{"type": "sunburst"}]])
fig.add_trace(go.Sunburst(
labels=labels,
parents=parents,
values=values,
))
fig.update_layout(title_text=title)
# 将plotly图形嵌入到tkinter中
from plotly.subplots import make_subplots
from plotly.offline import plot
import tempfile
# 创建临时文件
with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as f:
plot(fig, filename=f.name, auto_open=False)
html_path = f.name
# 在matplotlib中显示HTML
from matplotlib.pyplot import imshow
from PIL import Image
import io
# 这里无法直接显示HTML,给出提示
ax = self.figure.add_subplot(111)
ax.text(0.5, 0.5, f"旭日图已生成\n请在浏览器中打开: {html_path}",
horizontalalignment='center', verticalalignment='center')
ax.axis('off')
3.重置当前图形的参数
在reset_params(self)函数中添加。
elif self.current_graph_type == "sunburst":
self.sunburst_labels.delete(0, tk.END)
self.sunburst_labels.insert(0, "A,B,A1,A2,B1,B2;A,A,B,B,B,B")
self.sunburst_values.delete(0, tk.END)
self.sunburst_values.insert(0, "10,15,5,5,8,7")
self.sunburst_title.delete(0, tk.END)
self.sunburst_title.insert(0, "旭日图示例")
(十一)添加菜单(添加后的完整代码)如下:
def create_menu(self):
"""创建菜单栏"""
menubar = tk.Menu(self.root)
# 创建"图形类型"菜单
graph_menu = tk.Menu(menubar, tearoff=0)
graph_menu.add_command(label="饼图", command=self.show_pie_chart)
graph_menu.add_command(label="柱状图", command=self.show_bar_chart)
graph_menu.add_command(label="折线图", command=self.show_line_chart)
graph_menu.add_command(label="散点图", command=self.show_scatter_chart)
graph_menu.add_command(label="直方图", command=self.show_histogram)
# 新增的10种图形
graph_menu.add_separator()
graph_menu.add_command(label="箱线图", command=self.show_boxplot)
graph_menu.add_command(label="热力图", command=self.show_heatmap)
graph_menu.add_command(label="雷达图", command=self.show_radar_chart)
graph_menu.add_command(label="气泡图", command=self.show_bubble_chart)
graph_menu.add_command(label="面积图", command=self.show_area_chart)
graph_menu.add_command(label="堆叠柱状图", command=self.show_stacked_bar)
graph_menu.add_command(label="散点矩阵图", command=self.show_scatter_matrix)
graph_menu.add_command(label="词云图", command=self.show_wordcloud)
graph_menu.add_command(label="瀑布图", command=self.show_waterfall)
graph_menu.add_command(label="旭日图", command=self.show_sunburst)
menubar.add_cascade(label="图形类型", menu=graph_menu)
menubar.add_command(label="关于", command=self.show_about)
menubar.add_command(label="退出", command=self.root.quit)
self.root.config(menu=menubar)
三、图形可视化工具使用手册
(一)概述
本工具基于 Python 的 tkinter 和 matplotlib 库开发,提供直观的界面用于生成和定制各种图形。支持 15 种常用图形类型,包括饼图、柱状图、折线图、散点图、直方图、箱线图、热力图等。
(二)安装依赖
使用前需要安装以下库:
特别的,词云图需要wordcloud库,旭日图需要plotly库。
pip install matplotlib numpy pandas wordcloud plotly pillow
(三)图形类型与参数说明
1.饼图(Pie Chart)

2.柱状图(Bar Chart)

3.折线图(Line Chart)

4.散点图(Scatter Plot)

5.直方图(Histogram)

6.箱线图(Box Plot)

7.热力图(Heatmap)

8.雷达图(Radar Chart)

9.气泡图(Bubble Chart)

10.面积图(Area Chart)

11.堆叠柱状图(Stacked Bar Chart)

12.散点矩阵图(Scatter Matrix)

13.词云图(Word Cloud)
当如果没有安装wordcloud库时,会有提示:

安装之后,即可正常展示图形:

14.瀑布图(Waterfall Chart)

15.旭日图(Sunburst Chart)

路径是:C:/Users/lzm07/AppData/Local/Temp/tmpj2ytf0wp.html
具体路径跟自己的电脑有关(正常情况下,AppData是隐藏文件夹),同时,每次生成的html文件名不同。
(四)使用方法
- 运行程序后,默认显示饼图界面
- 通过菜单栏选择需要的图形类型
- 在左侧参数设置区修改图形参数
- 点击 "生成图形" 按钮更新右侧图形显示
- 点击 "重置参数" 按钮恢复默认设置
(五)注意事项
- 旭日图生成后会保存为 HTML 文件,需要在浏览器中打开查看
- 词云图需要安装额外的字体支持中文显示
- 所有图表支持中文显示,但确保系统已安装中文字体
四、完整代码
以下是包含所有新增图形和补充函数的完整代码:
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
import random
# 设置matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
class GraphVisualizerApp:
def __init__(self, root):
self.root = root
self.root.title("图形可视化工具")
self.root.geometry("1000x600")
# 创建菜单栏
self.create_menu()
# 创建主框架
self.main_frame = ttk.Frame(root)
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 创建参数设置区域和图形显示区域
self.setup_layout()
# 默认显示饼图
self.current_graph_type = "pie"
self.show_pie_chart()
def create_menu(self):
"""创建菜单栏"""
menubar = tk.Menu(self.root)
# 创建"图形类型"菜单
graph_menu = tk.Menu(menubar, tearoff=0)
graph_menu.add_command(label="饼图", command=self.show_pie_chart)
graph_menu.add_command(label="柱状图", command=self.show_bar_chart)
graph_menu.add_command(label="折线图", command=self.show_line_chart)
graph_menu.add_command(label="散点图", command=self.show_scatter_chart)
graph_menu.add_command(label="直方图", command=self.show_histogram)
# 新增的10种图形
graph_menu.add_separator()
graph_menu.add_command(label="箱线图", command=self.show_boxplot)
graph_menu.add_command(label="热力图", command=self.show_heatmap)
graph_menu.add_command(label="雷达图", command=self.show_radar_chart)
graph_menu.add_command(label="气泡图", command=self.show_bubble_chart)
graph_menu.add_command(label="面积图", command=self.show_area_chart)
graph_menu.add_command(label="堆叠柱状图", command=self.show_stacked_bar)
graph_menu.add_command(label="散点矩阵图", command=self.show_scatter_matrix)
graph_menu.add_command(label="词云图", command=self.show_wordcloud)
graph_menu.add_command(label="瀑布图", command=self.show_waterfall)
graph_menu.add_command(label="旭日图", command=self.show_sunburst)
menubar.add_cascade(label="图形类型", menu=graph_menu)
menubar.add_command(label="关于", command=self.show_about)
menubar.add_command(label="退出", command=self.root.quit)
self.root.config(menu=menubar)
def setup_layout(self):
"""设置界面布局"""
# 创建左右框架
left_frame = ttk.LabelFrame(self.main_frame, text="参数设置")
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=5, pady=5)
right_frame = ttk.LabelFrame(self.main_frame, text="图形显示")
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
# 参数设置区域 - 使用一个框架作为容器
self.param_frame = ttk.Frame(left_frame)
self.param_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 图形显示区域
self.figure = plt.figure(figsize=(6, 5), dpi=100)
self.canvas = FigureCanvasTkAgg(self.figure, master=right_frame)
self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
# 按钮区域
btn_frame = ttk.Frame(left_frame)
btn_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Button(btn_frame, text="生成图形", command=self.generate_graph).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="重置参数", command=self.reset_params).pack(side=tk.LEFT, padx=5)
def clear_param_frame(self):
"""清除参数设置区域的所有控件"""
for widget in self.param_frame.winfo_children():
widget.destroy()
def show_pie_chart(self):
"""显示饼图设置界面"""
self.current_graph_type = "pie"
self.clear_param_frame()
self.root.title("图形可视化工具 - 饼图")
ttk.Label(self.param_frame, text="数据标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.pie_labels = ttk.Entry(self.param_frame, width=30)
self.pie_labels.insert(0, "A,B,C,D,E")
self.pie_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据值(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.pie_values = ttk.Entry(self.param_frame, width=30)
self.pie_values.insert(0, "15,30,45,10,20")
self.pie_values.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.pie_title = ttk.Entry(self.param_frame, width=30)
self.pie_title.insert(0, "饼图示例")
self.pie_title.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="是否显示百分比:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.pie_show_percent = tk.BooleanVar(value=True)
ttk.Checkbutton(self.param_frame, variable=self.pie_show_percent).grid(row=3, column=1, sticky=tk.W, pady=5)
# 生成默认图形
self.generate_graph()
def show_bar_chart(self):
"""显示柱状图设置界面"""
self.current_graph_type = "bar"
self.clear_param_frame()
self.root.title("图形可视化工具 - 柱状图")
ttk.Label(self.param_frame, text="X轴标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.bar_labels = ttk.Entry(self.param_frame, width=30)
self.bar_labels.insert(0, "一月,二月,三月,四月,五月")
self.bar_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴值(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.bar_values = ttk.Entry(self.param_frame, width=30)
self.bar_values.insert(0, "65,70,80,90,85")
self.bar_values.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.bar_title = ttk.Entry(self.param_frame, width=30)
self.bar_title.insert(0, "柱状图示例")
self.bar_title.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.bar_xlabel = ttk.Entry(self.param_frame, width=30)
self.bar_xlabel.insert(0, "月份")
self.bar_xlabel.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.bar_ylabel = ttk.Entry(self.param_frame, width=30)
self.bar_ylabel.insert(0, "数值")
self.bar_ylabel.grid(row=4, column=1, pady=5)
# 生成默认图形
self.generate_graph()
def show_line_chart(self):
"""显示折线图设置界面"""
self.current_graph_type = "line"
self.clear_param_frame()
self.root.title("图形可视化工具 - 折线图")
ttk.Label(self.param_frame, text="X轴数据(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.line_x = ttk.Entry(self.param_frame, width=30)
self.line_x.insert(0, "1,2,3,4,5,6,7")
self.line_x.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴数据(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.line_y = ttk.Entry(self.param_frame, width=30)
self.line_y.insert(0, "65,59,80,81,56,55,70")
self.line_y.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.line_title = ttk.Entry(self.param_frame, width=30)
self.line_title.insert(0, "折线图示例")
self.line_title.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.line_xlabel = ttk.Entry(self.param_frame, width=30)
self.line_xlabel.insert(0, "X轴")
self.line_xlabel.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.line_ylabel = ttk.Entry(self.param_frame, width=30)
self.line_ylabel.insert(0, "Y轴")
self.line_ylabel.grid(row=4, column=1, pady=5)
ttk.Label(self.param_frame, text="线条颜色:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.line_color = ttk.Combobox(self.param_frame, values=["blue", "red", "green", "black", "purple"], width=27)
self.line_color.current(0)
self.line_color.grid(row=5, column=1, pady=5)
# 生成默认图形
self.generate_graph()
def show_scatter_chart(self):
"""显示散点图设置界面"""
self.current_graph_type = "scatter"
self.clear_param_frame()
self.root.title("图形可视化工具 - 散点图")
ttk.Label(self.param_frame, text="X轴数据(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.scatter_x = ttk.Entry(self.param_frame, width=30)
self.scatter_x.insert(0, "1,2,3,4,5,6,7")
self.scatter_x.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴数据(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.scatter_y = ttk.Entry(self.param_frame, width=30)
self.scatter_y.insert(0, "65,59,80,81,56,55,70")
self.scatter_y.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.scatter_title = ttk.Entry(self.param_frame, width=30)
self.scatter_title.insert(0, "散点图示例")
self.scatter_title.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.scatter_xlabel = ttk.Entry(self.param_frame, width=30)
self.scatter_xlabel.insert(0, "X轴")
self.scatter_xlabel.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.scatter_ylabel = ttk.Entry(self.param_frame, width=30)
self.scatter_ylabel.insert(0, "Y轴")
self.scatter_ylabel.grid(row=4, column=1, pady=5)
ttk.Label(self.param_frame, text="点的大小:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.scatter_size = ttk.Scale(self.param_frame, from_=10, to=200, orient=tk.HORIZONTAL, length=200)
self.scatter_size.set(50)
self.scatter_size.grid(row=5, column=1, pady=5)
# 生成默认图形
self.generate_graph()
def show_histogram(self):
"""显示直方图设置界面"""
self.current_graph_type = "histogram"
self.clear_param_frame()
self.root.title("图形可视化工具 - 直方图")
ttk.Label(self.param_frame, text="数据(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.hist_data = ttk.Entry(self.param_frame, width=30)
# 生成一些随机数据
random_data = [random.normalvariate(50, 15) for _ in range(100)]
self.hist_data.insert(0, ",".join([str(round(x, 1)) for x in random_data]))
self.hist_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.hist_title = ttk.Entry(self.param_frame, width=30)
self.hist_title.insert(0, "直方图示例")
self.hist_title.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.hist_xlabel = ttk.Entry(self.param_frame, width=30)
self.hist_xlabel.insert(0, "数值")
self.hist_xlabel.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.hist_ylabel = ttk.Entry(self.param_frame, width=30)
self.hist_ylabel.insert(0, "频率")
self.hist_ylabel.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="分箱数量:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.hist_bins = ttk.Scale(self.param_frame, from_=5, to=50, orient=tk.HORIZONTAL, length=200)
self.hist_bins.set(10)
self.hist_bins.grid(row=4, column=1, pady=5)
# 生成默认图形
self.generate_graph()
def show_boxplot(self):
"""显示箱线图设置界面"""
self.current_graph_type = "boxplot"
self.clear_param_frame()
self.root.title("图形可视化工具 - 箱线图")
ttk.Label(self.param_frame, text="数据集(多组用分号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.boxplot_data = ttk.Entry(self.param_frame, width=30)
self.boxplot_data.insert(0, "1,2,3,4,5,6,7;5,6,7,8,9,10,11;2,3,4,5,6,7,8")
self.boxplot_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="标签(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.boxplot_labels = ttk.Entry(self.param_frame, width=30)
self.boxplot_labels.insert(0, "数据组A,数据组B,数据组C")
self.boxplot_labels.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.boxplot_title = ttk.Entry(self.param_frame, width=30)
self.boxplot_title.insert(0, "箱线图示例")
self.boxplot_title.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="是否显示异常值:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.boxplot_showfliers = tk.BooleanVar(value=True)
ttk.Checkbutton(self.param_frame, variable=self.boxplot_showfliers).grid(row=3, column=1, sticky=tk.W, pady=5)
self.generate_graph()
def show_heatmap(self):
"""显示热力图设置界面"""
self.current_graph_type = "heatmap"
self.clear_param_frame()
self.root.title("图形可视化工具 - 热力图")
ttk.Label(self.param_frame, text="数据(用逗号分隔行,分号分隔列):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.heatmap_data = ttk.Entry(self.param_frame, width=30)
self.heatmap_data.insert(0, "1,2,3;4,5,6;7,8,9")
self.heatmap_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="行标签(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.heatmap_row_labels = ttk.Entry(self.param_frame, width=30)
self.heatmap_row_labels.insert(0, "A,B,C")
self.heatmap_row_labels.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="列标签(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.heatmap_col_labels = ttk.Entry(self.param_frame, width=30)
self.heatmap_col_labels.insert(0, "X,Y,Z")
self.heatmap_col_labels.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.heatmap_title = ttk.Entry(self.param_frame, width=30)
self.heatmap_title.insert(0, "热力图示例")
self.heatmap_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="颜色映射:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.heatmap_cmap = ttk.Combobox(self.param_frame, values=["viridis", "plasma", "inferno", "magma", "cividis"], width=27)
self.heatmap_cmap.current(0)
self.heatmap_cmap.grid(row=4, column=1, pady=5)
self.generate_graph()
def show_radar_chart(self):
"""显示雷达图设置界面"""
self.current_graph_type = "radar"
self.clear_param_frame()
self.root.title("图形可视化工具 - 雷达图")
ttk.Label(self.param_frame, text="指标名称(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.radar_labels = ttk.Entry(self.param_frame, width=30)
self.radar_labels.insert(0, "速度,力量,耐力,敏捷,智力,防御")
self.radar_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组(多组用分号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.radar_data = ttk.Entry(self.param_frame, width=30)
self.radar_data.insert(0, "70,80,60,90,50,75;60,90,80,70,65,85")
self.radar_data.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组名称(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.radar_group_names = ttk.Entry(self.param_frame, width=30)
self.radar_group_names.insert(0, "角色A,角色B")
self.radar_group_names.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.radar_title = ttk.Entry(self.param_frame, width=30)
self.radar_title.insert(0, "雷达图示例")
self.radar_title.grid(row=3, column=1, pady=5)
self.generate_graph()
def show_bubble_chart(self):
"""显示气泡图设置界面"""
self.current_graph_type = "bubble"
self.clear_param_frame()
self.root.title("图形可视化工具 - 气泡图")
ttk.Label(self.param_frame, text="X轴数据(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.bubble_x = ttk.Entry(self.param_frame, width=30)
self.bubble_x.insert(0, "1,2,3,4,5,6,7")
self.bubble_x.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴数据(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.bubble_y = ttk.Entry(self.param_frame, width=30)
self.bubble_y.insert(0, "65,59,80,81,56,55,70")
self.bubble_y.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="气泡大小(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.bubble_size = ttk.Entry(self.param_frame, width=30)
self.bubble_size.insert(0, "100,200,300,400,250,150,350")
self.bubble_size.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.bubble_title = ttk.Entry(self.param_frame, width=30)
self.bubble_title.insert(0, "气泡图示例")
self.bubble_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.bubble_xlabel = ttk.Entry(self.param_frame, width=30)
self.bubble_xlabel.insert(0, "X轴")
self.bubble_xlabel.grid(row=4, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.bubble_ylabel = ttk.Entry(self.param_frame, width=30)
self.bubble_ylabel.insert(0, "Y轴")
self.bubble_ylabel.grid(row=5, column=1, pady=5)
self.generate_graph()
def show_area_chart(self):
"""显示面积图设置界面"""
self.current_graph_type = "area"
self.clear_param_frame()
self.root.title("图形可视化工具 - 面积图")
ttk.Label(self.param_frame, text="X轴标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.area_xlabels = ttk.Entry(self.param_frame, width=30)
self.area_xlabels.insert(0, "一月,二月,三月,四月,五月,六月")
self.area_xlabels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组(多组用分号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.area_data = ttk.Entry(self.param_frame, width=30)
self.area_data.insert(0, "3,4,6,8,9,11;2,2,3,5,6,8;1,5,8,9,10,12")
self.area_data.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组名称(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.area_group_names = ttk.Entry(self.param_frame, width=30)
self.area_group_names.insert(0, "产品A,产品B,产品C")
self.area_group_names.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.area_title = ttk.Entry(self.param_frame, width=30)
self.area_title.insert(0, "面积图示例")
self.area_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="是否堆叠:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.area_stacked = tk.BooleanVar(value=True)
ttk.Checkbutton(self.param_frame, variable=self.area_stacked).grid(row=4, column=1, sticky=tk.W, pady=5)
self.generate_graph()
def show_stacked_bar(self):
"""显示堆叠柱状图设置界面"""
self.current_graph_type = "stacked_bar"
self.clear_param_frame()
self.root.title("图形可视化工具 - 堆叠柱状图")
ttk.Label(self.param_frame, text="X轴标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.stacked_xlabels = ttk.Entry(self.param_frame, width=30)
self.stacked_xlabels.insert(0, "一月,二月,三月,四月,五月")
self.stacked_xlabels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组(多组用分号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.stacked_data = ttk.Entry(self.param_frame, width=30)
self.stacked_data.insert(0, "10,15,20,17,22;15,12,19,21,25;5,7,11,9,13")
self.stacked_data.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="数据组名称(用逗号分隔):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.stacked_group_names = ttk.Entry(self.param_frame, width=30)
self.stacked_group_names.insert(0, "组A,组B,组C")
self.stacked_group_names.grid(row=2, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.stacked_title = ttk.Entry(self.param_frame, width=30)
self.stacked_title.insert(0, "堆叠柱状图示例")
self.stacked_title.grid(row=3, column=1, pady=5)
ttk.Label(self.param_frame, text="X轴标签:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.stacked_xlabel = ttk.Entry(self.param_frame, width=30)
self.stacked_xlabel.insert(0, "月份")
self.stacked_xlabel.grid(row=4, column=1, pady=5)
ttk.Label(self.param_frame, text="Y轴标签:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.stacked_ylabel = ttk.Entry(self.param_frame, width=30)
self.stacked_ylabel.insert(0, "数值")
self.stacked_ylabel.grid(row=5, column=1, pady=5)
self.generate_graph()
def show_scatter_matrix(self):
"""显示散点矩阵图设置界面"""
self.current_graph_type = "scatter_matrix"
self.clear_param_frame()
self.root.title("图形可视化工具 - 散点矩阵图")
ttk.Label(self.param_frame, text="数据集(多组用分号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.scatter_matrix_data = ttk.Entry(self.param_frame, width=30)
self.scatter_matrix_data.insert(0, "1,2,3,4,5;5,4,3,2,1;2,3,5,4,1")
self.scatter_matrix_data.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="变量名称(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.scatter_matrix_labels = ttk.Entry(self.param_frame, width=30)
self.scatter_matrix_labels.insert(0, "变量A,变量B,变量C")
self.scatter_matrix_labels.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.scatter_matrix_title = ttk.Entry(self.param_frame, width=30)
self.scatter_matrix_title.insert(0, "散点矩阵图示例")
self.scatter_matrix_title.grid(row=2, column=1, pady=5)
self.generate_graph()
def show_wordcloud(self):
"""显示词云图设置界面"""
self.current_graph_type = "wordcloud"
self.clear_param_frame()
self.root.title("图形可视化工具 - 词云图")
ttk.Label(self.param_frame, text="文本内容:").grid(row=0, column=0, sticky=tk.NW, pady=5)
self.wordcloud_text = scrolledtext.ScrolledText(self.param_frame, width=30, height=10)
self.wordcloud_text.insert(tk.END, "Python是一种广泛使用的高级编程语言,特别适合数据科学和机器学习。Python的语法简洁,易于学习,拥有丰富的库和工具。")
self.wordcloud_text.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.wordcloud_title = ttk.Entry(self.param_frame, width=30)
self.wordcloud_title.insert(0, "词云图示例")
self.wordcloud_title.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="最大词数:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.wordcloud_max_words = ttk.Entry(self.param_frame, width=30)
self.wordcloud_max_words.insert(0, "100")
self.wordcloud_max_words.grid(row=2, column=1, pady=5)
self.generate_graph()
def show_waterfall(self):
"""显示瀑布图设置界面"""
self.current_graph_type = "waterfall"
self.clear_param_frame()
self.root.title("图形可视化工具 - 瀑布图")
ttk.Label(self.param_frame, text="类别名称(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.waterfall_labels = ttk.Entry(self.param_frame, width=30)
self.waterfall_labels.insert(0, "起始,销售增长,成本增加,新产品,最终")
self.waterfall_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数值(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.waterfall_values = ttk.Entry(self.param_frame, width=30)
self.waterfall_values.insert(0, "1000,500,-300,200,0")
self.waterfall_values.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.waterfall_title = ttk.Entry(self.param_frame, width=30)
self.waterfall_title.insert(0, "瀑布图示例")
self.waterfall_title.grid(row=2, column=1, pady=5)
self.generate_graph()
def show_sunburst(self):
"""显示旭日图设置界面"""
self.current_graph_type = "sunburst"
self.clear_param_frame()
self.root.title("图形可视化工具 - 旭日图")
ttk.Label(self.param_frame, text="标签(用逗号分隔):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.sunburst_labels = ttk.Entry(self.param_frame, width=30)
self.sunburst_labels.insert(0, "A,B,A1,A2,B1,B2;A,A,B,B,B,B")
self.sunburst_labels.grid(row=0, column=1, pady=5)
ttk.Label(self.param_frame, text="数值(用逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=5)
self.sunburst_values = ttk.Entry(self.param_frame, width=30)
self.sunburst_values.insert(0, "10,15,5,5,8,7")
self.sunburst_values.grid(row=1, column=1, pady=5)
ttk.Label(self.param_frame, text="标题:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.sunburst_title = ttk.Entry(self.param_frame, width=30)
self.sunburst_title.insert(0, "旭日图示例")
self.sunburst_title.grid(row=2, column=1, pady=5)
self.generate_graph()
def generate_graph(self):
"""根据当前选择的图形类型生成图形"""
self.figure.clear()
try:
if self.current_graph_type == "pie":
# 饼图
labels = self.pie_labels.get().split(',')
values = [float(x) for x in self.pie_values.get().split(',')]
title = self.pie_title.get()
show_percent = self.pie_show_percent.get()
ax = self.figure.add_subplot(111)
autopct = '%1.1f%%' if show_percent else None
ax.pie(values, labels=labels, autopct=autopct, startangle=90)
ax.axis('equal') # 使饼图为正圆形
ax.set_title(title)
elif self.current_graph_type == "bar":
# 柱状图
labels = self.bar_labels.get().split(',')
values = [float(x) for x in self.bar_values.get().split(',')]
title = self.bar_title.get()
xlabel = self.bar_xlabel.get()
ylabel = self.bar_ylabel.get()
ax = self.figure.add_subplot(111)
ax.bar(labels, values)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
plt.xticks(rotation=45)
elif self.current_graph_type == "line":
# 折线图
x = [float(i) for i in self.line_x.get().split(',')]
y = [float(i) for i in self.line_y.get().split(',')]
title = self.line_title.get()
xlabel = self.line_xlabel.get()
ylabel = self.line_ylabel.get()
color = self.line_color.get()
ax = self.figure.add_subplot(111)
ax.plot(x, y, color=color)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
elif self.current_graph_type == "scatter":
# 散点图
x = [float(i) for i in self.scatter_x.get().split(',')]
y = [float(i) for i in self.scatter_y.get().split(',')]
title = self.scatter_title.get()
xlabel = self.scatter_xlabel.get()
ylabel = self.scatter_ylabel.get()
size = self.scatter_size.get()
ax = self.figure.add_subplot(111)
ax.scatter(x, y, s=size)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
elif self.current_graph_type == "histogram":
# 直方图
data = [float(i) for i in self.hist_data.get().split(',')]
title = self.hist_title.get()
xlabel = self.hist_xlabel.get()
ylabel = self.hist_ylabel.get()
bins = int(self.hist_bins.get())
ax = self.figure.add_subplot(111)
ax.hist(data, bins=bins)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
elif self.current_graph_type == "boxplot":
# 箱线图
data_sets = self.boxplot_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
labels = self.boxplot_labels.get().split(',')
title = self.boxplot_title.get()
showfliers = self.boxplot_showfliers.get()
ax = self.figure.add_subplot(111)
ax.boxplot(data, labels=labels, showfliers=showfliers)
ax.set_title(title)
elif self.current_graph_type == "heatmap":
# 热力图
data_str = self.heatmap_data.get().split(';')
data = []
for row in data_str:
data.append([float(x) for x in row.split(',')])
row_labels = self.heatmap_row_labels.get().split(',')
col_labels = self.heatmap_col_labels.get().split(',')
title = self.heatmap_title.get()
cmap = self.heatmap_cmap.get()
ax = self.figure.add_subplot(111)
im = ax.imshow(data, cmap=cmap)
# 设置坐标轴标签
ax.set_xticks(np.arange(len(col_labels)))
ax.set_yticks(np.arange(len(row_labels)))
ax.set_xticklabels(col_labels)
ax.set_yticklabels(row_labels)
# 添加颜色条
self.figure.colorbar(im)
ax.set_title(title)
elif self.current_graph_type == "radar":
# 雷达图
labels = self.radar_labels.get().split(',')
data_sets = self.radar_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
group_names = self.radar_group_names.get().split(',')
title = self.radar_title.get()
# 计算角度
angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False).tolist()
# 闭合雷达图
labels = labels + [labels[0]]
angles = angles + [angles[0]]
ax = self.figure.add_subplot(111, polar=True)
# 绘制每个数据组
for i, d in enumerate(data):
d = d + [d[0]] # 闭合数据
ax.plot(angles, d, 'o-', linewidth=2, label=group_names[i])
ax.fill(angles, d, alpha=0.25)
# 设置标签
ax.set_thetagrids(np.degrees(angles[:-1]), labels[:-1])
ax.set_title(title)
ax.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
elif self.current_graph_type == "bubble":
# 气泡图
x = [float(i) for i in self.bubble_x.get().split(',')]
y = [float(i) for i in self.bubble_y.get().split(',')]
size = [float(i) for i in self.bubble_size.get().split(',')]
title = self.bubble_title.get()
xlabel = self.bubble_xlabel.get()
ylabel = self.bubble_ylabel.get()
ax = self.figure.add_subplot(111)
scatter = ax.scatter(x, y, s=size, alpha=0.5)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
# 添加图例
handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6)
legend2 = ax.legend(handles, labels, loc="upper right", title="气泡大小")
elif self.current_graph_type == "area":
# 面积图
xlabels = self.area_xlabels.get().split(',')
data_sets = self.area_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
group_names = self.area_group_names.get().split(',')
title = self.area_title.get()
stacked = self.area_stacked.get()
ax = self.figure.add_subplot(111)
if stacked:
# 堆叠面积图
ax.stackplot(xlabels, data, labels=group_names)
else:
# 非堆叠面积图
for i, d in enumerate(data):
ax.fill_between(xlabels, d, alpha=0.5, label=group_names[i])
ax.set_title(title)
ax.legend(loc='upper left')
elif self.current_graph_type == "stacked_bar":
# 堆叠柱状图
xlabels = self.stacked_xlabels.get().split(',')
data_sets = self.stacked_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
group_names = self.stacked_group_names.get().split(',')
title = self.stacked_title.get()
xlabel = self.stacked_xlabel.get()
ylabel = self.stacked_ylabel.get()
ax = self.figure.add_subplot(111)
x = np.arange(len(xlabels))
width = 0.35
bottom = np.zeros(len(xlabels))
for i, d in enumerate(data):
ax.bar(x, d, width, bottom=bottom, label=group_names[i])
bottom += np.array(d)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.set_xticks(x)
ax.set_xticklabels(xlabels)
ax.legend()
elif self.current_graph_type == "scatter_matrix":
# 散点矩阵图
data_sets = self.scatter_matrix_data.get().split(';')
data = []
for dataset in data_sets:
data.append([float(x) for x in dataset.split(',')])
# 转置数据以匹配pandas DataFrame格式
data = np.array(data).T
labels = self.scatter_matrix_labels.get().split(',')
title = self.scatter_matrix_title.get()
# 使用pandas绘制散点矩阵图
import pandas as pd
df = pd.DataFrame(data, columns=labels)
ax = self.figure.add_subplot(111)
pd.plotting.scatter_matrix(df, alpha=0.8, figsize=(6, 6), diagonal='kde', ax=ax)
self.figure.suptitle(title)
elif self.current_graph_type == "wordcloud":
# 词云图
try:
from wordcloud import WordCloud
except ImportError:
messagebox.showerror("错误", "请先安装wordcloud库: pip install wordcloud")
return
text = self.wordcloud_text.get("1.0", tk.END)
title = self.wordcloud_title.get()
max_words = int(self.wordcloud_max_words.get())
ax = self.figure.add_subplot(111)
# 生成词云
wordcloud = WordCloud(max_words=max_words, background_color="white").generate(text)
ax.imshow(wordcloud, interpolation='bilinear')
ax.axis("off")
ax.set_title(title)
elif self.current_graph_type == "waterfall":
# 瀑布图
labels = self.waterfall_labels.get().split(',')
values = [float(x) for x in self.waterfall_values.get().split(',')]
title = self.waterfall_title.get()
# 计算累积值
is_total = [False] * len(values)
is_total[-1] = True # 最后一个是总计
# 创建一个新的DataFrame处理瀑布图数据
import pandas as pd
df = pd.DataFrame({
'label': labels,
'value': values,
'is_total': is_total
})
# 计算绝对数值
abs_values = []
prev = 0
for i, row in df.iterrows():
if row['is_total']:
abs_values.append(row['value'])
else:
abs_values.append(prev + row['value'])
prev = abs_values[-1]
df['abs_value'] = abs_values
ax = self.figure.add_subplot(111)
# 绘制瀑布图
for i, row in df.iterrows():
if row['is_total']:
ax.bar(i, row['abs_value'], color='blue')
elif row['value'] >= 0:
ax.bar(i, row['value'], bottom=row['abs_value']-row['value'], color='green')
else:
ax.bar(i, row['value'], bottom=row['abs_value'], color='red')
ax.set_xticks(range(len(df)))
ax.set_xticklabels(df['label'])
ax.set_title(title)
elif self.current_graph_type == "sunburst":
# 旭日图
try:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
except ImportError:
messagebox.showerror("错误", "请先安装plotly库: pip install plotly")
return
labels_str, parents_str = self.sunburst_labels.get().split(';')
labels = labels_str.split(',')
parents = parents_str.split(',')
values = [float(x) for x in self.sunburst_values.get().split(',')]
title = self.sunburst_title.get()
# 创建旭日图
fig = make_subplots(rows=1, cols=1, specs=[[{"type": "sunburst"}]])
fig.add_trace(go.Sunburst(
labels=labels,
parents=parents,
values=values,
))
fig.update_layout(title_text=title)
# 将plotly图形嵌入到tkinter中
from plotly.subplots import make_subplots
from plotly.offline import plot
import tempfile
# 创建临时文件
with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as f:
plot(fig, filename=f.name, auto_open=False)
html_path = f.name
# 在matplotlib中显示HTML
from matplotlib.pyplot import imshow
from PIL import Image
import io
# 这里无法直接显示HTML,给出提示
ax = self.figure.add_subplot(111)
ax.text(0.5, 0.5, f"旭日图已生成\n请在浏览器中打开: {html_path}",
horizontalalignment='center', verticalalignment='center')
ax.axis('off')
# 调整布局并绘制图形
self.figure.tight_layout()
self.canvas.draw()
except Exception as e:
messagebox.showerror("错误", f"生成图形时出错: {str(e)}")
def reset_params(self):
"""重置当前图形的参数"""
if self.current_graph_type == "pie":
self.pie_labels.delete(0, tk.END)
self.pie_labels.insert(0, "A,B,C,D,E")
self.pie_values.delete(0, tk.END)
self.pie_values.insert(0, "15,30,45,10,20")
self.pie_title.delete(0, tk.END)
self.pie_title.insert(0, "饼图示例")
self.pie_show_percent.set(True)
elif self.current_graph_type == "bar":
self.bar_labels.delete(0, tk.END)
self.bar_labels.insert(0, "一月,二月,三月,四月,五月")
self.bar_values.delete(0, tk.END)
self.bar_values.insert(0, "65,70,80,90,85")
self.bar_title.delete(0, tk.END)
self.bar_title.insert(0, "柱状图示例")
self.bar_xlabel.delete(0, tk.END)
self.bar_xlabel.insert(0, "月份")
self.bar_ylabel.delete(0, tk.END)
self.bar_ylabel.insert(0, "数值")
elif self.current_graph_type == "line":
self.line_x.delete(0, tk.END)
self.line_x.insert(0, "1,2,3,4,5,6,7")
self.line_y.delete(0, tk.END)
self.line_y.insert(0, "65,59,80,81,56,55,70")
self.line_title.delete(0, tk.END)
self.line_title.insert(0, "折线图示例")
self.line_xlabel.delete(0, tk.END)
self.line_xlabel.insert(0, "X轴")
self.line_ylabel.delete(0, tk.END)
self.line_ylabel.insert(0, "Y轴")
self.line_color.set("blue")
elif self.current_graph_type == "scatter":
self.scatter_x.delete(0, tk.END)
self.scatter_x.insert(0, "1,2,3,4,5,6,7")
self.scatter_y.delete(0, tk.END)
self.scatter_y.insert(0, "65,59,80,81,56,55,70")
self.scatter_title.delete(0, tk.END)
self.scatter_title.insert(0, "散点图示例")
self.scatter_xlabel.delete(0, tk.END)
self.scatter_xlabel.insert(0, "X轴")
self.scatter_ylabel.delete(0, tk.END)
self.scatter_ylabel.insert(0, "Y轴")
self.scatter_size.set(50)
elif self.current_graph_type == "histogram":
self.hist_data.delete(0, tk.END)
self.hist_data.insert(0, "1,2,2,3,3,3,4,4,4,4,5,5,5,5,5")
self.hist_title.delete(0, tk.END)
self.hist_title.insert(0, "直方图示例")
self.hist_xlabel.delete(0, tk.END)
self.hist_xlabel.insert(0, "数值")
self.hist_ylabel.delete(0, tk.END)
self.hist_ylabel.insert(0, "频率")
self.hist_bins.delete(0, tk.END)
self.hist_bins.insert(0, "5")
# 新增的10种图形重置代码
elif self.current_graph_type == "boxplot":
self.boxplot_data.delete(0, tk.END)
self.boxplot_data.insert(0, "1,2,3,4,5,6,7;5,6,7,8,9,10,11;2,3,4,5,6,7,8")
self.boxplot_labels.delete(0, tk.END)
self.boxplot_labels.insert(0, "数据组A,数据组B,数据组C")
self.boxplot_title.delete(0, tk.END)
self.boxplot_title.insert(0, "箱线图示例")
self.boxplot_showfliers.set(True)
elif self.current_graph_type == "heatmap":
self.heatmap_data.delete(0, tk.END)
self.heatmap_data.insert(0, "1,2,3;4,5,6;7,8,9")
self.heatmap_row_labels.delete(0, tk.END)
self.heatmap_row_labels.insert(0, "A,B,C")
self.heatmap_col_labels.delete(0, tk.END)
self.heatmap_col_labels.insert(0, "X,Y,Z")
self.heatmap_title.delete(0, tk.END)
self.heatmap_title.insert(0, "热力图示例")
self.heatmap_cmap.current(0)
elif self.current_graph_type == "radar":
self.radar_labels.delete(0, tk.END)
self.radar_labels.insert(0, "速度,力量,耐力,敏捷,智力,防御")
self.radar_data.delete(0, tk.END)
self.radar_data.insert(0, "70,80,60,90,50,75;60,90,80,70,65,85")
self.radar_group_names.delete(0, tk.END)
self.radar_group_names.insert(0, "角色A,角色B")
self.radar_title.delete(0, tk.END)
self.radar_title.insert(0, "雷达图示例")
elif self.current_graph_type == "bubble":
self.bubble_x.delete(0, tk.END)
self.bubble_x.insert(0, "1,2,3,4,5,6,7")
self.bubble_y.delete(0, tk.END)
self.bubble_y.insert(0, "65,59,80,81,56,55,70")
self.bubble_size.delete(0, tk.END)
self.bubble_size.insert(0, "100,200,300,400,250,150,350")
self.bubble_title.delete(0, tk.END)
self.bubble_title.insert(0, "气泡图示例")
self.bubble_xlabel.delete(0, tk.END)
self.bubble_xlabel.insert(0, "X轴")
self.bubble_ylabel.delete(0, tk.END)
self.bubble_ylabel.insert(0, "Y轴")
elif self.current_graph_type == "area":
self.area_xlabels.delete(0, tk.END)
self.area_xlabels.insert(0, "一月,二月,三月,四月,五月,六月")
self.area_data.delete(0, tk.END)
self.area_data.insert(0, "3,4,6,8,9,11;2,2,3,5,6,8;1,5,8,9,10,12")
self.area_group_names.delete(0, tk.END)
self.area_group_names.insert(0, "产品A,产品B,产品C")
self.area_title.delete(0, tk.END)
self.area_title.insert(0, "面积图示例")
self.area_stacked.set(True)
elif self.current_graph_type == "stacked_bar":
self.stacked_xlabels.delete(0, tk.END)
self.stacked_xlabels.insert(0, "一月,二月,三月,四月,五月")
self.stacked_data.delete(0, tk.END)
self.stacked_data.insert(0, "10,15,20,17,22;15,12,19,21,25;5,7,11,9,13")
self.stacked_group_names.delete(0, tk.END)
self.stacked_group_names.insert(0, "组A,组B,组C")
self.stacked_title.delete(0, tk.END)
self.stacked_title.insert(0, "堆叠柱状图示例")
self.stacked_xlabel.delete(0, tk.END)
self.stacked_xlabel.insert(0, "月份")
self.stacked_ylabel.delete(0, tk.END)
self.stacked_ylabel.insert(0, "数值")
elif self.current_graph_type == "scatter_matrix":
self.scatter_matrix_data.delete(0, tk.END)
self.scatter_matrix_data.insert(0, "1,2,3,4,5;5,4,3,2,1;2,3,5,4,1")
self.scatter_matrix_labels.delete(0, tk.END)
self.scatter_matrix_labels.insert(0, "变量A,变量B,变量C")
self.scatter_matrix_title.delete(0, tk.END)
self.scatter_matrix_title.insert(0, "散点矩阵图示例")
elif self.current_graph_type == "wordcloud":
self.wordcloud_text.delete("1.0", tk.END)
self.wordcloud_text.insert(tk.END, "Python是一种广泛使用的高级编程语言,特别适合数据科学和机器学习。Python的语法简洁,易于学习,拥有丰富的库和工具。")
self.wordcloud_title.delete(0, tk.END)
self.wordcloud_title.insert(0, "词云图示例")
self.wordcloud_max_words.delete(0, tk.END)
self.wordcloud_max_words.insert(0, "100")
elif self.current_graph_type == "waterfall":
self.waterfall_labels.delete(0, tk.END)
self.waterfall_labels.insert(0, "起始,销售增长,成本增加,新产品,最终")
self.waterfall_values.delete(0, tk.END)
self.waterfall_values.insert(0, "1000,500,-300,200,0")
self.waterfall_title.delete(0, tk.END)
self.waterfall_title.insert(0, "瀑布图示例")
elif self.current_graph_type == "sunburst":
self.sunburst_labels.delete(0, tk.END)
self.sunburst_labels.insert(0, "A,B,A1,A2,B1,B2;A,A,B,B,B,B")
self.sunburst_values.delete(0, tk.END)
self.sunburst_values.insert(0, "10,15,5,5,8,7")
self.sunburst_title.delete(0, tk.END)
self.sunburst_title.insert(0, "旭日图示例")
# 重新生成图形
self.generate_graph()
def show_about(self):
"""显示关于对话框"""
messagebox.showinfo("关于", "图形可视化工具 v1.0\n\n这是一个使用Python的tkinter和matplotlib库开发的图形可视化应用程序。\n\n支持饼图、柱状图、折线图、散点图和直方图等多种图形类型。")
if __name__ == "__main__":
root = tk.Tk()
app = GraphVisualizerApp(root)
root.mainloop()
这个图形可视化工具提供了简单易用的界面,让用户可以轻松创建和定制各种图形,无需编写代码。通过调整参数,用户可以获得满足需求的专业级图表。
作者:搏博