目录

Python实例题

题目

代码实现

实现原理

数据读取:

图表绘制:

模块化设计:

关键代码解析

数据读取与预处理

折线图绘制

热力图绘制

使用说明

安装依赖:

基本用法:

命令行使用:

扩展建议

增强功能:

样式优化:

高级功能:

用户界面:

Python实例题

题目

Python实现从excel读取数据并绘制成精美图像

代码实现

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from openpyxl import load_workbook
import os
import argparse

class ExcelChartGenerator:
    def __init__(self):
        # 设置中文字体支持
        plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
        plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题
        sns.set_style("whitegrid")  # 设置图表风格
    
    def read_excel(self, file_path, sheet_name=0, header=0):
        """读取Excel文件并返回DataFrame"""
        try:
            df = pd.read_excel(file_path, sheet_name=sheet_name, header=header)
            print(f"成功读取Excel文件: {file_path}")
            print(f"数据基本信息:")
            df.info()
            return df
        except Exception as e:
            print(f"读取Excel文件失败: {e}")
            return None
    
    def plot_line_chart(self, df, x_col, y_cols, title="折线图", 
                         xlabel="X轴", ylabel="Y轴", figsize=(10, 6), 
                         save_path=None, show=True):
        """绘制折线图"""
        plt.figure(figsize=figsize)
        
        if isinstance(y_cols, str):
            y_cols = [y_cols]
        
        for col in y_cols:
            plt.plot(df[x_col], df[col], marker='o', linewidth=2, label=col)
        
        plt.title(title, fontsize=15)
        plt.xlabel(xlabel, fontsize=12)
        plt.ylabel(ylabel, fontsize=12)
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.legend()
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()
    
    def plot_bar_chart(self, df, x_col, y_col, title="柱状图", 
                       xlabel="X轴", ylabel="Y轴", figsize=(10, 6), 
                       save_path=None, show=True, horizontal=False, color='skyblue'):
        """绘制柱状图"""
        plt.figure(figsize=figsize)
        
        if horizontal:
            plt.barh(df[x_col], df[y_col], color=color)
        else:
            plt.bar(df[x_col], df[y_col], color=color)
        
        plt.title(title, fontsize=15)
        plt.xlabel(xlabel, fontsize=12)
        plt.ylabel(ylabel, fontsize=12)
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()
    
    def plot_pie_chart(self, df, values_col, labels_col, title="饼图", 
                      figsize=(8, 6), save_path=None, show=True, autopct='%1.1f%%'):
        """绘制饼图"""
        plt.figure(figsize=figsize)
        
        plt.pie(df[values_col], labels=df[labels_col], autopct=autopct,
                shadow=True, startangle=90, textprops={'fontsize': 10})
        
        plt.axis('equal')  # 使饼图为正圆形
        plt.title(title, fontsize=15)
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()
    
    def plot_scatter_chart(self, df, x_col, y_col, title="散点图", 
                          xlabel="X轴", ylabel="Y轴", figsize=(10, 6), 
                          save_path=None, show=True, color='blue', alpha=0.7):
        """绘制散点图"""
        plt.figure(figsize=figsize)
        
        plt.scatter(df[x_col], df[y_col], color=color, alpha=alpha)
        
        plt.title(title, fontsize=15)
        plt.xlabel(xlabel, fontsize=12)
        plt.ylabel(ylabel, fontsize=12)
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()
    
    def plot_heatmap(self, df, title="热力图", figsize=(10, 8), 
                    save_path=None, show=True, annot=True, cmap='coolwarm'):
        """绘制热力图"""
        plt.figure(figsize=figsize)
        
        # 计算相关系数矩阵
        corr = df.corr()
        
        # 绘制热力图
        sns.heatmap(corr, annot=annot, cmap=cmap, square=True,
                    linewidths=.5, cbar_kws={"shrink": .8})
        
        plt.title(title, fontsize=15)
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()
    
    def plot_boxplot(self, df, column, group_by=None, title="箱线图", 
                    figsize=(10, 6), save_path=None, show=True):
        """绘制箱线图"""
        plt.figure(figsize=figsize)
        
        if group_by:
            df.boxplot(column=column, by=group_by)
            plt.title(title, fontsize=15)
            plt.suptitle('')  # 去掉pandas自动添加的标题
        else:
            plt.boxplot(df[column].dropna())
            plt.title(title, fontsize=15)
            plt.xticks([1], [column])
        
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()
    
    def plot_histogram(self, df, column, title="直方图", 
                      xlabel="X轴", ylabel="频率", figsize=(10, 6), 
                      save_path=None, show=True, bins=10, color='skyblue'):
        """绘制直方图"""
        plt.figure(figsize=figsize)
        
        plt.hist(df[column].dropna(), bins=bins, color=color, alpha=0.7)
        
        plt.title(title, fontsize=15)
        plt.xlabel(xlabel, fontsize=12)
        plt.ylabel(ylabel, fontsize=12)
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            print(f"图表已保存至: {save_path}")
        
        if show:
            plt.show()
        
        plt.close()


# 使用示例
if __name__ == "__main__":
    # 创建命令行参数解析器
    parser = argparse.ArgumentParser(description='Excel数据可视化工具')
    parser.add_argument('--file', type=str, help='Excel文件路径')
    parser.add_argument('--sheet', type=str, default=0, help='工作表名称或索引')
    parser.add_argument('--type', type=str, choices=['line', 'bar', 'pie', 'scatter', 'heatmap', 'boxplot', 'histogram'], 
                        help='图表类型')
    parser.add_argument('--x', type=str, help='X轴列名')
    parser.add_argument('--y', type=str, nargs='+', help='Y轴列名(可多个)')
    parser.add_argument('--title', type=str, default='数据可视化', help='图表标题')
    parser.add_argument('--output', type=str, help='图表保存路径')
    
    args = parser.parse_args()
    
    # 如果没有提供命令行参数,使用示例数据
    if not args.file:
        # 创建示例数据
        data = {
            '日期': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],
            '销售额': [12000, 19000, 15000, 21000, 25000],
            '利润': [3500, 5200, 4100, 6500, 7200],
            '成本': [8500, 13800, 10900, 14500, 17800]
        }
        
        df = pd.DataFrame(data)
        
        # 创建图表生成器实例
        generator = ExcelChartGenerator()
        
        # 绘制折线图
        generator.plot_line_chart(
            df, 
            x_col='日期', 
            y_cols=['销售额', '利润', '成本'], 
            title='月度销售数据趋势', 
            xlabel='日期', 
            ylabel='金额(元)'
        )
        
        # 绘制柱状图
        generator.plot_bar_chart(
            df, 
            x_col='日期', 
            y_col='销售额', 
            title='月度销售额', 
            xlabel='日期', 
            ylabel='销售额(元)',
            color='skyblue'
        )
        
        # 绘制饼图
        profit_data = {
            '部门': ['销售部', '研发部', '市场部', '财务部', '人力资源部'],
            '利润贡献': [45, 25, 15, 10, 5]
        }
        profit_df = pd.DataFrame(profit_data)
        
        generator.plot_pie_chart(
            profit_df, 
            values_col='利润贡献', 
            labels_col='部门', 
            title='各部门利润贡献占比'
        )
        
        # 绘制散点图
        scatter_data = {
            '广告投入': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
            '销售额': [150, 200, 250, 300, 350, 400, 450, 500, 550, 600]
        }
        scatter_df = pd.DataFrame(scatter_data)
        
        generator.plot_scatter_chart(
            scatter_df, 
            x_col='广告投入', 
            y_col='销售额', 
            title='广告投入与销售额关系', 
            xlabel='广告投入(万元)', 
            ylabel='销售额(万元)'
        )
        
        # 绘制热力图
        heatmap_data = {
            '温度': [20, 22, 25, 28, 30, 32, 31, 29, 27, 25],
            '湿度': [60, 65, 70, 75, 80, 85, 82, 78, 72, 68],
            '销量': [120, 135, 150, 165, 180, 195, 190, 175, 160, 145]
        }
        heatmap_df = pd.DataFrame(heatmap_data)
        
        generator.plot_heatmap(
            heatmap_df, 
            title='温度、湿度与销量的相关性热力图'
        )
        
        # 绘制箱线图
        boxplot_data = {
            '产品': ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B'],
            '评分': [85, 90, 88, 92, 87, 75, 78, 82, 80, 79]
        }
        boxplot_df = pd.DataFrame(boxplot_data)
        
        generator.plot_boxplot(
            boxplot_df, 
            column='评分', 
            group_by='产品', 
            title='不同产品评分分布'
        )
        
        # 绘制直方图
        hist_data = {
            '年龄': [22, 25, 28, 30, 32, 35, 38, 40, 42, 45, 48, 50, 52, 55, 58, 60]
        }
        hist_df = pd.DataFrame(hist_data)
        
        generator.plot_histogram(
            hist_df, 
            column='年龄', 
            title='年龄分布', 
            xlabel='年龄', 
            ylabel='人数',
            bins=5
        )
        
        print("已使用示例数据生成所有类型的图表")
    
    else:
        # 使用命令行参数指定的Excel文件
        if not args.type:
            print("请指定图表类型(--type)")
            sys.exit(1)
            
        if args.type in ['line', 'bar', 'scatter'] and not args.x:
            print(f"图表类型 {args.type} 需要指定X轴列名(--x)")
            sys.exit(1)
            
        if args.type in ['line', 'bar', 'scatter'] and not args.y:
            print(f"图表类型 {args.type} 需要指定Y轴列名(--y)")
            sys.exit(1)
            
        if args.type == 'pie' and (len(args.y) != 1 or not args.x):
            print("饼图需要指定一个Y轴列名(--y)和一个标签列名(--x)")
            sys.exit(1)
            
        # 创建图表生成器实例
        generator = ExcelChartGenerator()
        
        # 读取Excel文件
        df = generator.read_excel(args.file, sheet_name=args.sheet)
        
        if df is None:
            print("无法读取Excel文件,程序退出")
            sys.exit(1)
            
        # 根据指定的图表类型生成图表
        if args.type == 'line':
            generator.plot_line_chart(
                df, 
                x_col=args.x, 
                y_cols=args.y, 
                title=args.title,
                save_path=args.output
            )
            
        elif args.type == 'bar':
            generator.plot_bar_chart(
                df, 
                x_col=args.x, 
                y_col=args.y[0], 
                title=args.title,
                save_path=args.output
            )
            
        elif args.type == 'pie':
            generator.plot_pie_chart(
                df, 
                values_col=args.y[0], 
                labels_col=args.x, 
                title=args.title,
                save_path=args.output
            )
            
        elif args.type == 'scatter':
            generator.plot_scatter_chart(
                df, 
                x_col=args.x, 
                y_col=args.y[0], 
                title=args.title,
                save_path=args.output
            )
            
        elif args.type == 'heatmap':
            generator.plot_heatmap(
                df, 
                title=args.title,
                save_path=args.output
            )
            
        elif args.type == 'boxplot':
            generator.plot_boxplot(
                df, 
                column=args.y[0], 
                group_by=args.x if args.x else None,
                title=args.title,
                save_path=args.output
            )
            
        elif args.type == 'histogram':
            generator.plot_histogram(
                df, 
                column=args.y[0], 
                title=args.title,
                save_path=args.output
            )    

实现原理

这个 Excel 数据可视化工具基于以下核心技术实现:

  • 数据读取

    • 使用 pandas 读取 Excel 文件
    • 支持指定工作表和表头行
  • 图表绘制

    • 基于 matplotlib 和 seaborn 库
    • 提供多种图表类型(折线图、柱状图、饼图等)
    • 自定义图表样式和布局
  • 模块化设计

    • 每个图表类型对应一个独立方法
    • 统一的参数接口和样式配置
    • 支持图表保存和显示

关键代码解析

数据读取与预处理

def read_excel(self, file_path, sheet_name=0, header=0):
    try:
        df = pd.read_excel(file_path, sheet_name=sheet_name, header=header)
        print(f"成功读取Excel文件: {file_path}")
        df.info()  # 打印数据基本信息
        return df
    except Exception as e:
        print(f"读取Excel文件失败: {e}")
        return None

折线图绘制

def plot_line_chart(self, df, x_col, y_cols, title="折线图", 
                    xlabel="X轴", ylabel="Y轴", figsize=(10, 6), 
                    save_path=None, show=True):
    plt.figure(figsize=figsize)
    
    for col in y_cols:
        plt.plot(df[x_col], df[col], marker='o', linewidth=2, label=col)
    
    plt.title(title, fontsize=15)
    plt.xlabel(xlabel, fontsize=12)
    plt.ylabel(ylabel, fontsize=12)
    plt.grid(True, linestyle='--', alpha=0.7)
    plt.legend()
    plt.tight_layout()
    
    if save_path:
        plt.savefig(save_path, dpi=300, bbox_inches='tight')
    
    if show:
        plt.show()
    
    plt.close()

热力图绘制

def plot_heatmap(self, df, title="热力图", figsize=(10, 8), 
                save_path=None, show=True, annot=True, cmap='coolwarm'):
    plt.figure(figsize=figsize)
    
    # 计算相关系数矩阵
    corr = df.corr()
    
    # 使用seaborn绘制热力图
    sns.heatmap(corr, annot=annot, cmap=cmap, square=True,
                linewidths=.5, cbar_kws={"shrink": .8})
    
    plt.title(title, fontsize=15)
    plt.tight_layout()
    
    if save_path:
        plt.savefig(save_path, dpi=300, bbox_inches='tight')
    
    if show:
        plt.show()
    
    plt.close()

使用说明

  • 安装依赖

pip install pandas matplotlib seaborn openpyxl argparse
  • 基本用法

# 创建实例
generator = ExcelChartGenerator()

# 读取Excel数据
df = generator.read_excel("data.xlsx")

# 绘制折线图
generator.plot_line_chart(
    df, 
    x_col="日期", 
    y_cols=["销售额", "利润"], 
    title="销售趋势分析"
)
  • 命令行使用

# 使用示例数据生成所有类型的图表
python excel_chart_generator.py

# 从Excel文件读取数据并生成柱状图
python excel_chart_generator.py --file sales_data.xlsx --sheet Sheet1 --type bar --x 产品 --y 销量 --title "产品销量对比" --output sales_bar.png

扩展建议

  • 增强功能

    • 添加 3D 图表支持
    • 实现交互式图表(使用 plotly)
    • 支持图表组合和子图
  • 样式优化

    • 添加更多预设样式主题
    • 支持自定义颜色和字体
    • 优化中文显示效果
  • 高级功能

    • 添加数据预处理和清洗功能
    • 实现统计分析和趋势预测
    • 支持导出为 PDF 或其他格式
  • 用户界面

    • 开发 Web 界面(Flask/Django)
    • 制作桌面应用(PyQt/Tkinter)
    • 添加图形化参数配置界面
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐