基于Plotly在Python中实现每日新增数据的3D动画折线图
用Plotly实现3D动画折线图(逐行扩展+涨跌幅色彩映射)
数据预处理
基于你提供的股票数据生成代码,先将涨跌幅数据转换为累计净值(初始值100),并整理成适合Plotly 3D图的格式:
import yfinance as yf import pandas as pd import plotly.graph_objects as go # 生成股票数据(原始代码) stocks = ["AAPL", "MSFT"] df_stocks = pd.DataFrame() for stock in stocks: df = yf.download(stock, start="2022-01-01", end="2022-07-01", group_by='ticker') df['perct'] = df['Close'].pct_change() df_stocks[stock] = df['perct'] df_stocks.iloc[0] = 0 df_stocks += 1 df_stocks = df_stocks.cumprod()*100 df_stocks -= 100 # 转换为累计净值(初始值100) df_net_value = 100 + df_stocks # 转换成长格式,方便处理每个数据点 df_long = df_net_value.reset_index().melt(id_vars='Date', var_name='Stock', value_name='NetValue') # 关联涨跌幅数据(用于颜色映射) df_long['Change'] = df_stocks.reset_index().melt(id_vars='Date', var_name='Stock', value_name='Change')['Change'] # 给股票分配Y轴数值(3D图需要数值型Y轴) stock_y_map = {"AAPL": 0, "MSFT": 1} df_long['Y'] = df_long['Stock'].map(stock_y_map)
构建动画帧
为每一天生成一个帧,每个帧包含从初始日到当前日的所有数据点,同时动态扩展X轴范围:
# 初始化帧列表 frames = [] # 获取所有日期 dates = df_long['Date'].unique() # 生成初始帧(仅第一天数据) initial_data = df_long[df_long['Date'] == dates[0]] frames.append(go.Frame( data=[go.Scatter3d( x=initial_data['Date'], y=initial_data['Y'], z=initial_data['NetValue'], mode='lines+markers', marker=dict( size=6, color=initial_data['Change'], colorscale=[[0, '#8B0000'], [0.5, '#FFFFFF'], [1, '#006400']], cmin=df_long['Change'].min(), cmax=df_long['Change'].max(), colorbar=dict(title='涨跌幅(%)') ), line=dict(width=3) )], name=str(dates[0]) )) # 生成后续帧 for i in range(1, len(dates)): current_data = df_long[df_long['Date'] <= dates[i]] frames.append(go.Frame( data=[go.Scatter3d( x=current_data['Date'], y=current_data['Y'], z=current_data['NetValue'], mode='lines+markers', marker=dict( size=6, color=current_data['Change'], colorscale=[[0, '#8B0000'], [0.5, '#FFFFFF'], [1, '#006400']], cmin=df_long['Change'].min(), cmax=df_long['Change'].max(), colorbar=dict(title='涨跌幅(%)') ), line=dict(width=3) )], name=str(dates[i]), layout=go.Layout( scene=dict( xaxis=dict(range=[dates[0], dates[i]]) ) ) ))
构建完整图表并添加控制组件
设置图表布局,添加播放/暂停按钮,完成动画配置:
# 初始布局 fig = go.Figure( data=frames[0]['data'], frames=frames, layout=go.Layout( title='股票累计净值3D动画折线图', scene=dict( xaxis=dict(title='日期', type='date'), yaxis=dict(title='股票', tickvals=[0,1], ticktext=['AAPL','MSFT']), zaxis=dict(title='累计净值(初始100)'), camera=dict(eye=dict(x=1.5, y=1.5, z=0.5)) ), updatemenus=[dict( type='buttons', showactive=False, buttons=[dict( label='播放', method='animate', args=[None, dict( frame=dict(duration=300, redraw=True), transition=dict(duration=50), fromcurrent=True )] ), dict( label='暂停', method='animate', args=[[None], dict( frame=dict(duration=0, redraw=False), transition=dict(duration=0) )] )] )] ) ) # 显示图表 fig.show()
关键说明
- 逐行扩展数据:每个帧包含从初始日到当前日的全部数据,X轴范围随帧动态更新,确保始终显示已添加的所有日期。
- 色彩映射:自定义颜色刻度将负涨跌幅(下跌)映射为深红色系,正涨跌幅(上涨)映射为深绿色系,数值越极端颜色越深。
- 3D布局:Y轴用数值映射股票名称,Z轴展示累计净值,可通过拖拽视角调整查看角度。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

