Python 绘制基金和股票数据的季度变化对比散点图

背景

  • 我们有两种数据(基金和股票),两个时间点(20200630和20200930),以及三个特殊变量。
  • 我们需要绘制6幅图(3个变量 * 2个时间点)在一个画布上,每个图都包含基金和股票的对比,并且横向对比季度变化(即0630和0930的对比)。由于基金和股票的坐标系不同,我们需要左右两个纵轴分别表示基金和股票。
  • 我们将使用seaborn包和莫兰迪色系,由于莫兰迪色系不是matplotlib内置的,这里我们假设使用seaborn的柔和颜色。

步骤

  • 准备数据:假设我们有两个DataFrame,分别代表两个时间点的数据,每个DataFrame都有基金和股票的数据,并且有相同的行索引(1-1000)和列(变量)。基金和股票的数据是分开的,所以我们需要分别从两个DataFrame中提取基金和股票的三个特殊变量。

  • 我们假设三个特殊变量的列名已知,例如对于基金,变量名为[‘fund_var1’, ‘fund_var2’, ‘fund_var3’],对于股票,变量名为[‘stock_var1’, ‘stock_var2’, ‘stock_var3’]。

  • 创建画布:6幅图,我们可以安排成2行3列,因为有两个时间点(0630和0930)和三个变量。每个子图中,我们将绘制两个时间点的基金和股票的数据。但是注意,每个子图对应一个变量,横轴是时间(两个时间点),由于基金和股票的数据量级可能不同,所以我们需要双y轴:左边是基金,右边是股票。

  • 为了区分两个时间点,我们可以用不同的颜色(莫兰迪色系中的两种颜色)分别表示0630和0930。

  • 为了区分基金和股票,我们使用同一个横坐标(两个时间点),但是纵坐标分别用左右轴。

  • 我们将在每个子图的右上角添加图例,最后保存为pdf和png格式。

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from pathlib import Path

# 设置中文字体和莫兰迪色系
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

# 创建莫兰迪色系
morandi_colors = ['#9B9B9B', '#D8BFAA', '#8FAADC', '#A8D8B9', '#F4A582', '#B39DDB']

# 创建模拟数据
np.random.seed(42)  # 保证可重复性

# 生成模拟数据
dates = pd.date_range('2022-01-01', periods=1000, freq='D')
fund_data_0630 = pd.DataFrame({
    'var1': np.random.normal(100, 15, 1000),
    'var2': np.random.normal(50, 8, 1000),
    'var3': np.random.normal(200, 25, 1000),
    'volume': np.random.uniform(1000, 5000, 1000)
}, index=range(1, 1001))

fund_data_0930 = pd.DataFrame({
    'var1': np.random.normal(105, 16, 1000),
    'var2': np.random.normal(52, 9, 1000),
    'var3': np.random.normal(210, 26, 1000),
    'volume': np.random.uniform(1200, 5500, 1000)
}, index=range(1, 1001))

stock_data_0630 = pd.DataFrame({
    'var1': np.random.normal(25, 5, 1000),
    'var2': np.random.normal(15, 3, 1000),
    'var3': np.random.normal(80, 12, 1000),
    'volume': np.random.uniform(50000, 200000, 1000)
}, index=range(1, 1001))

stock_data_0930 = pd.DataFrame({
    'var1': np.random.normal(26, 5.5, 1000),
    'var2': np.random.normal(16, 3.2, 1000),
    'var3': np.random.normal(85, 13, 1000),
    'volume': np.random.uniform(55000, 220000, 1000)
}, index=range(1, 1001))

# 创建输出目录
output_dir = Path('financial_plots')
output_dir.mkdir(exist_ok=True)

# 创建图形和子图
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
fig.suptitle('基金与股票季度变化对比分析\n(0630 vs 0930)', fontsize=16, fontweight='bold', y=0.95)

# 定义三个特殊变量
special_vars = ['var1', 'var2', 'var3']
quarters = ['0630', '0930']

# 绘制散点图
for i, var in enumerate(special_vars):
    # 第一行:0630季度的对比
    ax1 = axes[0, i]
    
    # 基金数据 - 左轴
    fund_scatter1 = ax1.scatter(fund_data_0630.index, fund_data_0630[var], 
                               c=morandi_colors[0], alpha=0.7, s=30, 
                               label='基金 0630', marker='o')
    
    # 股票数据 - 右轴
    ax1_right = ax1.twinx()
    stock_scatter1 = ax1_right.scatter(stock_data_0630.index, stock_data_0630[var], 
                                      c=morandi_colors[1], alpha=0.7, s=30, 
                                      label='股票 0630', marker='s')
    
    ax1.set_title(f'{var} - 0630季度', fontsize=12, fontweight='bold')
    ax1.set_xlabel('序列索引')
    ax1.set_ylabel('基金数值', color=morandi_colors[0])
    ax1_right.set_ylabel('股票数值', color=morandi_colors[1])
    
    # 设置坐标轴颜色
    ax1.tick_params(axis='y', labelcolor=morandi_colors[0])
    ax1_right.tick_params(axis='y', labelcolor=morandi_colors[1])
    
    # 第二行:0930季度的对比
    ax2 = axes[1, i]
    
    # 基金数据 - 左轴
    fund_scatter2 = ax2.scatter(fund_data_0930.index, fund_data_0930[var], 
                               c=morandi_colors[2], alpha=0.7, s=30, 
                               label='基金 0930', marker='o')
    
    # 股票数据 - 右轴
    ax2_right = ax2.twinx()
    stock_scatter2 = ax2_right.scatter(stock_data_0930.index, stock_data_0930[var], 
                                      c=morandi_colors[3], alpha=0.7, s=30, 
                                      label='股票 0930', marker='s')
    
    ax2.set_title(f'{var} - 0930季度', fontsize=12, fontweight='bold')
    ax2.set_xlabel('序列索引')
    ax2.set_ylabel('基金数值', color=morandi_colors[2])
    ax2_right.set_ylabel('股票数值', color=morandi_colors[3])
    
    # 设置坐标轴颜色
    ax2.tick_params(axis='y', labelcolor=morandi_colors[2])
    ax2_right.tick_params(axis='y', labelcolor=morandi_colors[3])

# 添加整体图例
handles = [
    plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=morandi_colors[0], markersize=8, label='基金 0630'),
    plt.Line2D([0], [0], marker='s', color='w', markerfacecolor=morandi_colors[1], markersize=8, label='股票 0630'),
    plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=morandi_colors[2], markersize=8, label='基金 0930'),
    plt.Line2D([0], [0], marker='s', color='w', markerfacecolor=morandi_colors[3], markersize=8, label='股票 0930')
]

fig.legend(handles=handles, loc='upper right', bbox_to_anchor=(0.98, 0.98), 
           frameon=True, fancybox=True, shadow=True, ncol=2)

# 调整布局
plt.tight_layout()
plt.subplots_adjust(top=0.9)

# 保存图片
plt.savefig(output_dir / 'fund_stock_comparison.pdf', dpi=300, bbox_inches='tight')
plt.savefig(output_dir / 'fund_stock_comparison.png', dpi=300, bbox_inches='tight')

print(f"图片已保存到: {output_dir.absolute()}")
print("生成的文件:")
print(f"  - {output_dir / 'fund_stock_comparison.pdf'}")
print(f"  - {output_dir / 'fund_stock_comparison.png'}")

plt.show()

# 添加统计分析
print("\n统计分析:")
print("=" * 50)
for var in special_vars:
    print(f"\n变量 {var}:")
    print(f"基金 0630: 均值={fund_data_0630[var].mean():.2f}, 标准差={fund_data_0630[var].std():.2f}")
    print(f"基金 0930: 均值={fund_data_0930[var].mean():.2f}, 标准差={fund_data_0930[var].std():.2f}")
    print(f"股票 0630: 均值={stock_data_0630[var].mean():.2f}, 标准差={stock_data_0630[var].std():.2f}")
    print(f"股票 0930: 均值={stock_data_0930[var].mean():.2f}, 标准差={stock_data_0930[var].std():.2f}")

主要特点

运行此代码将生成一个包含6个散点图的综合对比分析,清晰地展示基金和股票数据在不同季度和不同变量上的变化趋势。

模块化分离

数据生成部分

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from pathlib import Path

def generate_financial_data():
    """
    生成模拟的基金和股票季度数据
    """
    np.random.seed(42)  # 保证可重复性
    
    # 生成0630季度数据
    fund_data_0630 = pd.DataFrame({
        'var1': np.random.normal(100, 15, 1000),
        'var2': np.random.normal(50, 8, 1000),
        'var3': np.random.normal(200, 25, 1000),
        'volume': np.random.uniform(1000, 5000, 1000),
        'returns': np.random.normal(0.05, 0.02, 1000)
    }, index=range(1, 1001))
    
    fund_data_0930 = pd.DataFrame({
        'var1': np.random.normal(105, 16, 1000),
        'var2': np.random.normal(52, 9, 1000),
        'var3': np.random.normal(210, 26, 1000),
        'volume': np.random.uniform(1200, 5500, 1000),
        'returns': np.random.normal(0.06, 0.025, 1000)
    }, index=range(1, 1001))
    
    stock_data_0630 = pd.DataFrame({
        'var1': np.random.normal(25, 5, 1000),
        'var2': np.random.normal(15, 3, 1000),
        'var3': np.random.normal(80, 12, 1000),
        'volume': np.random.uniform(50000, 200000, 1000),
        'returns': np.random.normal(0.08, 0.03, 1000)
    }, index=range(1, 1001))
    
    stock_data_0930 = pd.DataFrame({
        'var1': np.random.normal(26, 5.5, 1000),
        'var2': np.random.normal(16, 3.2, 1000),
        'var3': np.random.normal(85, 13, 1000),
        'volume': np.random.uniform(55000, 220000, 1000),
        'returns': np.random.normal(0.09, 0.035, 1000)
    }, index=range(1, 1001))
    
    return {
        'fund_0630': fund_data_0630,
        'fund_0930': fund_data_0930,
        'stock_0630': stock_data_0630,
        'stock_0930': stock_data_0930
    }

def print_data_summary(data_dict):
    """
    打印数据摘要统计信息
    """
    print("数据摘要统计:")
    print("=" * 50)
    
    for data_name, data in data_dict.items():
        print(f"\n{data_name}:")
        print(f"  形状: {data.shape}")
        print(f"  变量: {list(data.columns)}")
        print(f"  索引范围: {data.index.min()} - {data.index.max()}")
        
        # 打印前三个特殊变量的统计信息
        for var in ['var1', 'var2', 'var3']:
            if var in data.columns:
                print(f"  {var}: 均值={data[var].mean():.2f}, 标准差={data[var].std():.2f}")

绘图函数部分

def create_comparison_plots(data_dict, special_vars=None, output_dir='financial_plots'):
    """
    创建基金和股票季度变化对比散点图
    
    参数:
    - data_dict: 包含四个数据集的字典
    - special_vars: 要绘制的特殊变量列表
    - output_dir: 输出目录名称
    """
    # 设置中文字体和莫兰迪色系
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
    plt.rcParams['axes.unicode_minus'] = False
    
    # 莫兰迪色系
    morandi_colors = ['#9B9B9B', '#D8BFAA', '#8FAADC', '#A8D8B9', '#F4A582', '#B39DDB']
    
    # 默认的特殊变量
    if special_vars is None:
        special_vars = ['var1', 'var2', 'var3']
    
    # 创建输出目录
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)
    
    # 创建图形和子图
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    fig.suptitle('基金与股票季度变化对比分析\n(0630 vs 0930)', fontsize=16, fontweight='bold', y=0.95)
    
    # 提取数据
    fund_0630 = data_dict['fund_0630']
    fund_0930 = data_dict['fund_0930']
    stock_0630 = data_dict['stock_0630']
    stock_0930 = data_dict['stock_0930']
    
    # 绘制散点图
    for i, var in enumerate(special_vars):
        # 第一行:0630季度的对比
        ax1 = axes[0, i]
        
        # 基金数据 - 左轴
        fund_scatter1 = ax1.scatter(fund_0630.index, fund_0630[var], 
                                   c=morandi_colors[0], alpha=0.7, s=30, 
                                   label='基金 0630', marker='o')
        
        # 股票数据 - 右轴
        ax1_right = ax1.twinx()
        stock_scatter1 = ax1_right.scatter(stock_0630.index, stock_0630[var], 
                                          c=morandi_colors[1], alpha=0.7, s=30, 
                                          label='股票 0630', marker='s')
        
        ax1.set_title(f'{var} - 0630季度', fontsize=12, fontweight='bold')
        ax1.set_xlabel('序列索引')
        ax1.set_ylabel('基金数值', color=morandi_colors[0])
        ax1_right.set_ylabel('股票数值', color=morandi_colors[1])
        
        # 设置坐标轴颜色
        ax1.tick_params(axis='y', labelcolor=morandi_colors[0])
        ax1_right.tick_params(axis='y', labelcolor=morandi_colors[1])
        
        # 第二行:0930季度的对比
        ax2 = axes[1, i]
        
        # 基金数据 - 左轴
        fund_scatter2 = ax2.scatter(fund_0930.index, fund_0930[var], 
                                   c=morandi_colors[2], alpha=0.7, s=30, 
                                   label='基金 0930', marker='o')
        
        # 股票数据 - 右轴
        ax2_right = ax2.twinx()
        stock_scatter2 = ax2_right.scatter(stock_0930.index, stock_0930[var], 
                                          c=morandi_colors[3], alpha=0.7, s=30, 
                                          label='股票 0930', marker='s')
        
        ax2.set_title(f'{var} - 0930季度', fontsize=12, fontweight='bold')
        ax2.set_xlabel('序列索引')
        ax2.set_ylabel('基金数值', color=morandi_colors[2])
        ax2_right.set_ylabel('股票数值', color=morandi_colors[3])
        
        # 设置坐标轴颜色
        ax2.tick_params(axis='y', labelcolor=morandi_colors[2])
        ax2_right.tick_params(axis='y', labelcolor=morandi_colors[3])
    
    # 添加整体图例
    handles = [
        plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=morandi_colors[0], 
                  markersize=8, label='基金 0630'),
        plt.Line2D([0], [0], marker='s', color='w', markerfacecolor=morandi_colors[1], 
                  markersize=8, label='股票 0630'),
        plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=morandi_colors[2], 
                  markersize=8, label='基金 0930'),
        plt.Line2D([0], [0], marker='s', color='w', markerfacecolor=morandi_colors[3], 
                  markersize=8, label='股票 0930')
    ]
    
    fig.legend(handles=handles, loc='upper right', bbox_to_anchor=(0.98, 0.98), 
               frameon=True, fancybox=True, shadow=True, ncol=2)
    
    # 调整布局
    plt.tight_layout()
    plt.subplots_adjust(top=0.9)
    
    # 保存图片
    pdf_path = output_path / 'fund_stock_comparison.pdf'
    png_path = output_path / 'fund_stock_comparison.png'
    
    plt.savefig(pdf_path, dpi=300, bbox_inches='tight')
    plt.savefig(png_path, dpi=300, bbox_inches='tight')
    
    print(f"图片已保存到: {output_path.absolute()}")
    print(f"生成的文件:")
    print(f"  - {pdf_path}")
    print(f"  - {png_path}")
    
    plt.show()
    
    return fig

def create_advanced_plots(data_dict, special_vars=None, output_dir='financial_plots'):
    """
    创建更高级的对比图表(可选功能)
    """
    if special_vars is None:
        special_vars = ['var1', 'var2', 'var3']
    
    # 这里可以添加其他类型的图表
    # 比如箱线图、密度图等
    
    print("高级图表功能已准备就绪")

主程序部分

def main():
    """
    主函数:生成数据并创建图表
    """
    # 1. 生成数据
    print("正在生成模拟数据...")
    financial_data = generate_financial_data()
    
    # 2. 打印数据摘要
    print_data_summary(financial_data)
    
    # 3. 创建对比图表
    print("\n正在创建对比图表...")
    fig = create_comparison_plots(
        data_dict=financial_data,
        special_vars=['var1', 'var2', 'var3'],
        output_dir='financial_analysis_output'
    )
    
    # 4. 可选:创建高级图表
    # create_advanced_plots(financial_data)
    
    print("\n程序执行完成!")

# 运行主程序
if __name__ == "__main__":
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值