在 matplotlib 的子图中进行缩放绘图。

4
这个问题来自于这篇教程,您可以在这里找到。 我希望我的图表看起来像下面这张,但是使用时间序列数据,缩放的数据不是x_lim, y_lim的数据,而是来自于另一个数据源。 enter image description here 因此,在上面的绘图中,我想要来自另一个数据源的日内数据,下面的绘图将是某只股票每日的数据。但由于它们都有不同的数据源,我无法使用限制进行缩放。为此,我将使用雅虎数据读取器获取每日数据,使用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坐标时遇到了问题。使用上述代码,我得到了以下错误:

类型错误:无法将数组数据从dtype('O')转换为dtype('float64'),根据规则“safe”

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

我所做的是将x值设置为日期df[1:2].index,将y值设置为价格df[2:3].Close

enter image description here

是否将df转换为数组并绘制图形是我的唯一选择?如果有其他方法可以让ConnectionPatch正常工作,请指导一下。


df.dtypes

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

你解决了已有答案的问题吗?底部的图表显示要使用蜡烛图,但如果你真的画出一个图表,由于数据跨越五年,蜡烛太小以至于没有任何可视化效果。因此,每月蜡烛图和每日缩放图的时间序列是模糊的。你对此有什么想法?我正在准备一个答案。 - r-beginners
@r-beginners 图表应该在主图(紫色)中显示每日的情况。这将展示详细的长期图表(可能为12个月)。然后,小段会被放大,其中一个子图上会有较小时间框架内的每日图表,比如说2个月(绿色图)。另一个子图则会显示最新蜡烛的日内图表(橙色)。我希望我已经回答了你的问题。谢谢。 - Slartibartfast
1
@Slartibartfast 我的回答中包含了完成这个任务所需的所有工具。我将其与你的问题代码一起粘贴在了我的回答中,请查看我的回答编辑部分。 - Cimbali
除非我漏掉了什么:) - Cimbali
我需要在折线图上填写相关时间段吗?其中左上角大约为2个月,右上角为最新的蜡烛图,城市图大约为1年?我看到你已经得到的答案已经根据你的评论进行了更新。 - r-beginners
1个回答

4

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

有三种方法可以计算这个数字:

  • 要么使用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中使用了pct_change的值,但又用Close 值进行了绘图。

当然,如果您想要像示例中那样获得框的底部,则最好使用轴变换而不是数据变换来表示坐标:

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()

enter image description here


“将所有内容放在一起”脚本缺少导入,可能还缺少其他部分。很难理解如何将它们全部组合在一起。 - merit_2
2
@merit_2,它没有使用除我提到的问题和“mplfinance”之外的任何其他导入。但是我可以添加它们,当然可以。 - Cimbali

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接