You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于两个含重复日期的DataFrame绘制苹果股价与地震事件关联图表并解决标记重叠问题

嘿,我来帮你搞定这个需求!咱们可以用Plotly的Scatter轨迹高效添加地震标记,同时通过数据关联和偏移处理解决重叠问题,一步一步来:

核心思路

  1. 关联地震与当日股价:通过合并两个DataFrame,让每个地震事件匹配到当日的苹果收盘价,这样标记就能精准定位到股价位置。
  2. 解决单日多地震重叠:给同日期的地震标记添加微小的y轴偏移,让它们在收盘价上下均匀分布,既不偏离股价太多,又能清晰区分每个事件。
  3. 高效渲染:用单个Scatter轨迹批量添加所有标记,避免循环添加的低效问题。

完整实现代码

import pandas as pd
import plotly.graph_objects as go

if __name__ == '__main__':
    # 加载数据
    df_apple_stock = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
    df_earthquakes = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/earthquakes-23k.csv')

    # 统一日期格式为UTC
    df_apple_stock['Date'] = pd.to_datetime(df_apple_stock['Date'], utc=True)
    df_earthquakes['Date'] = pd.to_datetime(df_earthquakes['Date'], utc=True)

    # 筛选2015-2016年的地震数据
    start_day = pd.to_datetime('02/17/2015', utc=True)
    end_day = pd.to_datetime('12/31/2016', utc=True)
    df_earthquakes = df_earthquakes[df_earthquakes['Date'].between(start_day, end_day)]

    # --- 关键步骤1:关联地震与当日股价 ---
    # 只保留股票数据中的日期和收盘价,用于合并
    stock_price_map = df_apple_stock[['Date', 'AAPL.Close']]
    # 合并地震数据与股价数据,只保留有对应股价的地震(过滤周末/节假日的地震)
    merged_df = pd.merge(df_earthquakes, stock_price_map, on='Date', how='inner')

    # --- 关键步骤2:处理单日多地震的偏移 ---
    # 计算每个日期的地震数量
    merged_df['daily_count'] = merged_df.groupby('Date')['Date'].transform('count')
    # 标记每个地震在当日的顺序
    merged_df['day_index'] = merged_df.groupby('Date').cumcount()
    # 设置偏移步长(这里用收盘价的0.5%,避免偏移过大)
    offset_step = merged_df['AAPL.Close'] * 0.005
    # 计算每个标记的y轴偏移:让同日期的标记在收盘价上下对称分布
    merged_df['y_offset'] = (merged_df['day_index'] - (merged_df['daily_count'] - 1)/2) * offset_step
    # 最终标记的y坐标 = 当日收盘价 + 偏移
    merged_df['marker_y'] = merged_df['AAPL.Close'] + merged_df['y_offset']

    # --- 绘制股价线 ---
    fig = go.Figure(data=[go.Scatter(
        x=df_apple_stock['Date'], 
        y=df_apple_stock['AAPL.Close'],
        mode='lines',
        name='AAPL Close Price',
        hovertemplate= '<b>%{x}</b><br>' +
                      'Open: $%{customdata[1]:.2f}<br>' +
                      'Close: $%{y:.2f}<br>' +
                      'High: $%{customdata[2]:.2f}<br>' +
                      'Low: $%{customdata[3]:.2f}<br>' +
                      'Volume: %{customdata[5]:,}',
        customdata=df_apple_stock.values
    )])

    # --- 添加地震标记 ---
    fig.add_trace(go.Scatter(
        x=merged_df['Date'],
        y=merged_df['marker_y'],
        mode='markers',
        name='Earthquakes',
        marker=dict(
            color='#ff4444',
            size=merged_df['Magnitude'] * 2,  # 震级越大,标记越大,直观区分
            symbol='triangle-up',
            opacity=0.8
        ),
        hovertemplate='<b>Earthquake Event</b><br>' +
                      'Date: %{x}<br>' +
                      'Magnitude: %{customdata[0]}<br>' +
                      'Latitude: %{customdata[1]:.4f}<br>' +
                      'Longitude: %{customdata[2]:.4f}<br>' +
                      '当日收盘价: $%{customdata[3]:.2f}',
        customdata=merged_df[['Magnitude', 'Latitude', 'Longitude', 'AAPL.Close']].values
    ))

    # --- 优化布局 ---
    fig.update_layout(
        title='AAPL Stock Price with Earthquake Markers (2015-2016)',
        xaxis_title='Date',
        yaxis_title='AAPL Close Price ($)',
        hovermode='x unified',  # 鼠标悬停时显示同一日期的所有信息
        legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1)
    )

    fig.show()

关键细节解释

  1. 数据关联:通过pd.merge将地震数据和股票收盘价绑定,确保每个地震标记都能对应到当日的股价位置,解决了你之前无法关联y值的问题。
  2. 重叠处理:
    • 先统计每个日期的地震数量,再给每个地震分配一个顺序索引。
    • 用对称偏移的方式,让同日期的标记在收盘价上下均匀分布,比如当日有3个地震,偏移分别为-0.5%、0、+0.5%的收盘价,既避免重叠,又保持和股价的关联。
  3. 高效渲染:用单个Scatter轨迹一次性添加所有地震标记,比循环添加annotation高效得多,即使数据量大也能流畅运行。
  4. 交互优化:
    • 标记大小和震级挂钩,直观展示地震强度。
    • 悬停模板包含所有关键信息,hovermode='x unified'让你在查看股价时同时看到当日所有地震事件。

可选优化

  • 如果觉得偏移量太大/太小,可以调整offset_step的比例(比如把0.005改成0.003或0.007)。
  • 对于极端大的地震,可以用不同的标记颜色或符号突出显示。
  • 如果想过滤掉小震级的事件,可以添加merged_df = merged_df[merged_df['Magnitude'] >= 5]这样的筛选条件。

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 12:07:27