使用Tiingo API绘制股票散点图时遇TypeError问题求助
问题分析与解决
问题背景
使用Tiingo API获取4只股票(TSLA、ADDYY、UPS、PFE)2020-2021年数据后,成功绘制了4个独立的日涨跌幅直方图,但运行散点图代码时触发TypeError: no numerical data to plot错误,期望得到对应4只股票的独立散点图。
可正常运行的直方图代码
import datetime import pandas_datareader as pdr import pandas as pd api_key='thisisasecret' tickers = ['TSLA', 'ADDYY', 'UPS', 'PFE'] start="2020-1-1" end="2021-7-1" df = pdr.tiingo.TiingoDailyReader(tickers, start=start, end=end, api_key=api_key) all_data = df.read() all_data import matplotlib.pyplot as plt daily_close_px = all_data[['adjClose']].reset_index().pivot('date', 'symbol', 'adjClose') daily_pct_change = daily_close_px.pct_change() daily_pct_change.hist(bins=50, sharex=True, figsize=(12,8)) plt.show()
报错的散点图代码
all_data.plot(kind='scatter',x='date',y='adjClose') plt.title('Stock Scatter Analysis') plt.xlabel('date') plt.ylabel('closing price') plt.show()
错误原因
- 索引与列的混淆:Tiingo返回的
all_data是多层索引(MultiIndex),date和symbol属于索引层级,不是普通数据列。plot.scatter要求x参数指定的是数值型数据列,直接传入'date'会导致pandas无法找到对应数值数据。 - 数据结构不匹配:直方图代码中通过
pivot将数据整理成了每列对应一只股票的宽表结构,pandas的hist方法能自动为每列生成子图;但原始all_data是包含所有股票的长表,直接调用plot.scatter无法自动拆分生成多子图,且date为datetime类型不符合散点图的数值要求。
解决方法
方法1:基于透视后的宽表绘制(推荐)
复用直方图中已经处理好的daily_close_px宽表,手动创建子图并绘制:
import matplotlib.pyplot as plt # 创建2x2子图布局 fig, axes = plt.subplots(2, 2, figsize=(12, 8)) axes = axes.flatten() # 遍历每只股票绘制散点图 for idx, ticker in enumerate(daily_close_px.columns): # 将datetime类型的日期转为秒级时间戳(数值型) x_timestamp = daily_close_px.index.astype('int64') // 10**9 axes[idx].scatter(x_timestamp, daily_close_px[ticker]) axes[idx].set_title(f'{ticker} 调整收盘价 vs 日期') axes[idx].set_ylabel('调整收盘价') # 将x轴时间戳格式化为日期显示 axes[idx].xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%Y-%m')) axes[idx].tick_params(axis='x', rotation=45) plt.tight_layout() plt.show()
方法2:直接处理原始长表数据
如果不想依赖透视后的宽表,可先重置索引拆分数据再绘制:
import matplotlib.pyplot as plt # 重置索引,将date和symbol转为普通列 all_data_reset = all_data.reset_index() # 创建2x2子图布局 fig, axes = plt.subplots(2, 2, figsize=(12, 8)) axes = axes.flatten() # 按股票分组绘制 for idx, (ticker, group) in enumerate(all_data_reset.groupby('symbol')): # 日期转时间戳 x_timestamp = group['date'].astype('int64') // 10**9 axes[idx].scatter(x_timestamp, group['adjClose']) axes[idx].set_title(f'{ticker} 调整收盘价 vs 日期') axes[idx].set_ylabel('调整收盘价') # 格式化x轴日期 axes[idx].xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%Y-%m')) axes[idx].tick_params(axis='x', rotation=45) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者x_X_X_x
相关产品推荐
相关产品推荐

