matplotlib:使用SHARED X轴创建两个(堆叠的)子图,但使用SEPARATE Y轴值

时间:2012-04-04 07:55:45

标签: python matplotlib

我在Ubuntu 10.0.4上使用matplotlib 1.2.x和Python 2.6.5。我正在尝试创建一个由顶部图和底部图组成的单个图。

X轴是时间序列的日期。顶部图包含数据的烛台图,底部图应包含条形图 - 具有自己的Y轴(也在左侧 - 与顶部图相同)。这两个图不应该重叠。

这是我到目前为止所做的一些片段。

datafile = r'/var/tmp/trz12.csv'
r = mlab.csv2rec(datafile, delimiter=',', names=('dt', 'op', 'hi', 'lo', 'cl', 'vol', 'oi'))

mask = (r["dt"] >= datetime.date(startdate)) & (r["dt"] <= datetime.date(enddate))
selected = r[mask]
plotdata = zip(date2num(selected['dt']), selected['op'], selected['cl'], selected['hi'], selected['lo'], selected['vol'], selected['oi'])

# Setup charting 
mondays = WeekdayLocator(MONDAY)        # major ticks on the mondays
alldays    = DayLocator()               # minor ticks on the days
weekFormatter = DateFormatter('%b %d')  # Eg, Jan 12
dayFormatter = DateFormatter('%d')      # Eg, 12
monthFormatter = DateFormatter('%b %y')

# every Nth month
months = MonthLocator(range(1,13), bymonthday=1, interval=1)

fig = pylab.figure()
fig.subplots_adjust(bottom=0.1)
ax = fig.add_subplot(111)
ax.xaxis.set_major_locator(months)#mondays
ax.xaxis.set_major_formatter(monthFormatter) #weekFormatter
ax.format_xdata = mdates.DateFormatter('%Y-%m-%d')
ax.format_ydata = price
ax.grid(True)

candlestick(ax, plotdata, width=0.5, colorup='g', colordown='r', alpha=0.85)

ax.xaxis_date()
ax.autoscale_view()
pylab.setp( pylab.gca().get_xticklabels(), rotation=45, horizontalalignment='right')

# Add volume data 
# Note: the code below OVERWRITES the bottom part of the first plot
# it should be plotted UNDERNEATH the first plot - but somehow, that's not happening
fig.subplots_adjust(hspace=0.15)
ay = fig.add_subplot(212)
volumes = [ x[-2] for x in plotdata]
ay.bar(range(len(plotdata)), volumes, 0.05)

pylab.show()

我已经设法使用上面的代码显示这两个图,但是底图有两个问题:

  1. 它完全覆盖了第一个(顶部)情节的底部 - 几乎就像第二个情节在第一个情节的同一个“画布”上绘制 - 我无法看到发生在哪里/为什么

  2. 它用自己的indice覆盖现有的X轴,两个图之间的X轴值(日期)应该是SHARED。

  3. 我的代码中出错了什么?有人可以发现导致第二(底部)情节覆盖第一个(顶部)情节的原因 - 我该如何解决这个问题?

    以下是上述代码创建的图表的屏幕截图:

    faulty plot

    [[编辑]]

    按照hwlau的建议修改代码后,这是新的情节。它比第一个更好,因为这两个图是分开的,但是仍然存在以下问题:

    1. X轴应该是两个图的共享(即X轴应仅显示第二个[底部]图)

    2. 第二幅图的Y值似乎不正确

    3. partly correct plot

      我认为这些问题应该很容易解决,但是我的matplotlib fu目前还不是很好,因为我最近才开始用matplotlib编程。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:12)

您的代码似乎存在一些问题:

  1. 如果您正在使用figure.add_subplots 它可能有subplot(nrows, ncols, plotNum)的签名 更明显的是你的第一个情节要求1排 和1列,第二个图要求2行和 1列。因此,你的第一个情节正在填补整个数字。 而不是fig.add_subplot(111)后跟fig.add_subplot(212) 使用fig.add_subplot(211)后跟fig.add_subplot(212)

  2. 应使用add_subplot

  3. sharex=first_axis_instance命令中共享轴

    我已经汇总了一个你应该能够运行的例子:

    import matplotlib.pyplot as plt
    import matplotlib.ticker as mticker
    import matplotlib.dates as mdates
    
    
    import datetime as dt
    
    
    n_pts = 10
    dates = [dt.datetime.now() + dt.timedelta(days=i) for i in range(n_pts)]
    
    ax1 = plt.subplot(2, 1, 1)
    ax1.plot(dates, range(10))
    
    ax2 = plt.subplot(2, 1, 2, sharex=ax1)
    ax2.bar(dates, range(10, 20))
    
    # Now format the x axis. This *MUST* be done after all sharex commands are run.
    
    # put no more than 10 ticks on the date axis.  
    ax1.xaxis.set_major_locator(mticker.MaxNLocator(10))
    # format the date in our own way.
    ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
    
    # rotate the labels on both date axes
    for label in ax1.xaxis.get_ticklabels():
        label.set_rotation(30)
    for label in ax2.xaxis.get_ticklabels():
        label.set_rotation(30)
    
    # tweak the subplot spacing to fit the rotated labels correctly
    plt.subplots_adjust(hspace=0.35, bottom=0.125)
    
    plt.show()
    

    希望有所帮助。

答案 1 :(得分:6)

您应该更改此行:

ax = fig.add_subplot(111)

ax = fig.add_subplot(211)

原始命令意味着有一行和一列,因此它占据整个图形。所以你的第二张图fig.add_subplot(212)覆盖了第一张图的下半部分。

修改

如果您不想要两个图之间的差距,请使用subplots_adjust()来更改子图边距的大小。

答案 2 :(得分:2)

来自@Pelson的例子,简化。

import matplotlib.pyplot as plt
import datetime as dt

#Two subplots that share one x axis
fig,ax=plt.subplots(2,sharex=True)

#plot data
n_pts = 10
dates = [dt.datetime.now() + dt.timedelta(days=i) for i in range(n_pts)]
ax[0].bar(dates, range(10, 20))
ax[1].plot(dates, range(10))

#rotate and format the dates on the x axis
fig.autofmt_xdate()

共享x轴的子图创建在一行中,当您需要两个以上的子图时,这很方便:

fig, ax = plt.subplots(number_of_subplots, sharex=True)

要在x轴上正确格式化日期,我们只需使用fig.autofmt_xdate()

即可

shared x xaxis

有关其他信息,请参阅pylab示例中的shared axis demodate demo。 这个例子在Python3,matplotlib 1.5.1

上运行