【问题标题】:Plotting in a zooming in matplotlib subplot绘制放大 matplotlib 子图
【发布时间】:2021-11-06 12:29:51
【问题描述】:

这个问题来自本教程找到here: 我希望我的情节看起来像下面的情节,但有时间序列数据和缩放数据不是x_lim , y_lim 数据,而是来自不同的来源。

所以在上面的图中,我想要来自不同来源的盘中数据,下面的图将是某些股票的每日数据。但是因为它们都有不同的来源,所以我不能使用限制来缩放。为此,我将每天使用 yahoo datareader,盘中使用 yfinance。

代码:

import pandas as pd
from pandas_datareader import data as web
from matplotlib.patches import ConnectionPatch

df = web.DataReader('goog', 'yahoo')
df.Close = pd.to_numeric(df['Close'], errors='coerce')

fig = plt.figure(figsize=(6, 5))
plt.subplots_adjust(bottom = 0., left = 0, top = 1., right = 1)
sub1 = fig.add_subplot(2,2,1)
sub1 = df.Close.plot()

sub2 = fig.add_subplot(2,1,2) # two rows, two columns, second cell
df.Close.pct_change().plot(ax =sub2)
sub2.plot(theta, y, color = 'orange')
con1 = ConnectionPatch(xyA=(df[1:2].index, df[2:3].Close), coordsA=sub1.transData, 
                       xyB=(df[4:5].index, df[5:6].Close), coordsB=sub2.transData, color = 'green')
fig.add_artist(con1)

xy 坐标有问题。通过上面的代码,我得到了:

TypeError:无法将数组数据从 dtype('O') 转换为 dtype('float64') 根据规则“安全”

xyA=(df[1:2].index, df[2:3].Close)

我在这里所做的是我的 xvalue 是日期 df[1:2].index 而我的 y 值是价格 df[2:3].Close

是否将 df 转换为数组,然后在这里绘制我唯一的选择?如果有任何其他方法可以让ConnectionPatch 正常工作,请告知。


df.dtypes

High         float64
Low          float64
Open         float64
Close        float64
Volume         int64
Adj Close    float64
dtype: object

【问题讨论】:

  • 您是否使用已有的答案解决了问题?底部的图表说要使用烛台图,但如果您实际绘制图表,由于数据跨越五年,蜡烛太小而无法产生任何可视化效果。因此,每月烛台和每日缩放图的时间序列是不明确的。您对此有何看法?我正在准备一个答案。
  • @r-beginners 该图应在主图中显示每日图(紫色)。这将显示详细的长期图表(可能是 12 个月)。然后,在上面的两个子图中(绿色图)之一中,一小部分将在较小的时间范围内使用日线图进行缩放,例如 2 个月。另一个将有最新蜡烛(橙色)的盘中图。我希望我已经回答了。谢谢
  • @Slartibartfast 所有的工具都在我的回答中。我将它与您问题中的代码粘贴在一起,请参阅我的答案中的编辑。
  • 除非我当然错过了什么:)
  • 是否需要在左上2个月左右、右上最新蜡烛、城市图1年左右的折线图上填写相关时间段?我看到您已经根据您的 cmets 更新了您的答案。

标签: python python-3.x pandas matplotlib


【解决方案1】:

matplotlib 日期的绘制方式是将日期转换为浮点数,从 1970-1-1 的 0 开始,即 POSIX 时间戳为零。它与那个时间戳不同,因为它的分辨率不同,即“1”是一天而不是一秒。

有 3 种方法来计算这个数字,

  • 要么使用matplotlib.dates.date2num
  • 或使用.toordinal(),它会为您提供正确的分辨率并删除对应于 1970-1-1 的偏移量,
  • 或获取 POSIX 时间戳并除以一天中的秒数:
df['Close'] = pd.to_numeric(df['Close'], errors='coerce')
df['Change'] = df['Close'].pct_change()

con1 = ConnectionPatch(xyA=(df.index[0].toordinal() - pd.Timestamp(0).toordinal(), df['Close'].iloc[0]), coordsA=sub1.transData,
                       xyB=(df.index[1].toordinal() - pd.Timestamp(0).toordinal(), df['Change'].iloc[1]), coordsB=sub2.transData, color='green')
fig.add_artist(con1)

con2 = ConnectionPatch(xyA=(df.index[-1].timestamp() / 86_400, df['Close'].iloc[-1]), coordsA=sub1.transData,
                       xyB=(df.index[-1].timestamp() / 86_400, df['Change'].iloc[-1]), coordsB=sub2.transData, color='green')
fig.add_artist(con2)

您还需要确保您使用的是目标轴范围内的值,在您的示例中,您在 sub2 上使用 Close 值,其中包含 pct_change'd 值。

当然,如果您想要在示例中的框的底部,则使用轴变换而不是数据变换来表示坐标会更容易:

from matplotlib.dates import date2num

con1 = ConnectionPatch(xyA=(0, 0), coordsA=sub1.transAxes,
                       xyB=(date2num(df.index[1]), df['Change'].iloc[1]), coordsB=sub2.transData, color='green')
fig.add_artist(con1)

con2 = ConnectionPatch(xyA=(1, 0), coordsA=sub1.transAxes,
                       xyB=(date2num(df.index[-1]), df['Change'].iloc[-1]), coordsB=sub2.transData, color='green')
fig.add_artist(con2)

要绘制烛台图,我建议使用 mplfinance(以前的 matplotlib.finance)包:

import mplfinance as mpf
sub3 = fig.add_subplot(2, 2, 2)
mpf.plot(df.iloc[30:70], type='candle', ax=sub3)

将所有这些放在一个脚本中,它可能看起来像这样:

import pandas as pd, mplfinance as mpf, matplotlib.pyplot as plt
from pandas_datareader import data as web
from matplotlib.patches import ConnectionPatch
from matplotlib.dates import date2num, ConciseDateFormatter, AutoDateLocator
from matplotlib.ticker import PercentFormatter

# Get / compute data
df = web.DataReader('goog', 'yahoo')
df['Close'] = pd.to_numeric(df['Close'], errors='coerce')
df['Change'] = df['Close'].pct_change()

# Pick zoom range
zoom_start = df.index[30]
zoom_end = df.index[30 + 8 * 5] # 8 weeks ~ 2 months

# Create figures / axes
fig = plt.figure(figsize=(18, 12))
top_left = fig.add_subplot(2, 2, 1)
top_right = fig.add_subplot(2, 2, 2)
bottom = fig.add_subplot(2, 1, 2)
fig.subplots_adjust(hspace=.35)

# Plot all 3 data
df['Close'].plot(ax=bottom, linewidth=1, rot=0, title='Daily closing value', color='purple')
bottom.set_ylim(0)

df.loc[zoom_start:zoom_end, 'Change'].plot(ax=top_left, linewidth=1, rot=0, title='Daily Change, zoomed')
top_left.yaxis.set_major_formatter(PercentFormatter())

# Here instead of df.loc[...] use your intra-day data
mpf.plot(df.loc[zoom_start:zoom_end], type='candle', ax=top_right, xrotation=0, show_nontrading=True)
top_right.set_title('Last day OHLC')

# Put ConciseDateFormatters on all x-axes for fancy date display
for ax in fig.axes:
    locator = AutoDateLocator()
    ax.xaxis.set_major_locator(locator)
    ax.xaxis.set_major_formatter(ConciseDateFormatter(locator))

# Add the connection patches
fig.add_artist(ConnectionPatch(
    xyA=(0, 0), coordsA=top_left.transAxes,
    xyB=(date2num(zoom_start), df.loc[zoom_start, 'Close']), coordsB=bottom.transData,
    color='green'
))

fig.add_artist(ConnectionPatch(
    xyA=(1, 0), coordsA=top_left.transAxes,
    xyB=(date2num(zoom_end), df.loc[zoom_end, 'Close']), coordsB=bottom.transData,
    color='green'
))

plt.show()

【讨论】:

  • “将所有内容放在一起”脚本缺少导入,可能还有其他部分。很难将它们放在一起。
  • @merit_2 除了我提到的问题和mplfinance 之外,它没有使用任何其他导入。但我可以添加它们,当然。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-16
  • 2011-03-24
  • 2021-10-30
  • 2021-03-08
  • 1970-01-01
  • 1970-01-01
  • 2016-01-07
相关资源
最近更新 更多