简体   繁体   English

matplotlib:创建两个具有共享 X 轴但独立 Y 轴值的(堆叠)子图

[英]matplotlib: Creating two (stacked) subplots with SHARED X axis but SEPARATE Y axis values

I am using matplotlib 1.2.x and Python 2.6.5 on Ubuntu 10.0.4.我在 Ubuntu 10.0.4 上使用 matplotlib 1.2.x 和 Python 2.6.5。 I am trying to create a SINGLE plot that consists of a top plot and a bottom plot.我正在尝试创建一个由顶部 plot 和底部 plot 组成的 SINGLE plot。

The X axis is the date of the time series. X 轴是时间序列的日期。 The top plot contains a candlestick plot of the data, and the bottom plot should consist of a bar type plot - with its own Y axis (also on the left - same as the top plot).顶部 plot 包含数据的烛台 plot,底部 plot 应包含条形类型 plot - 具有自己的 Y 轴(也在左侧 - 与顶部图相同)。 These two plots should NOT OVERLAP.这两个图不应重叠。

Here is a snippet of what I have done so far.这是我到目前为止所做的片段。

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

I have managed to display the two plots using the code above, however, there are two problems with the bottom plot:我已经设法使用上面的代码显示了两个图,但是底部 plot 有两个问题:

  1. It COMPLETELY OVERWRITES the bottom part of the first (top) plot - almost as though the second plot was drawing on the same 'canvas' as the first plot - I can't see where/why that is happening.它完全覆盖了第一个(顶部)plot 的底部 - 几乎就像第二个 plot 在与第一个 plot 相同的“画布”上绘制一样 - 我看不到发生的位置/原因。

  2. It OVERWRITES the existing X axis with its own indice, the X axis values (dates) should be SHARED between the two plots.它用自己的索引覆盖现有的 X 轴,X 轴值(日期)应该在两个图之间共享。

What am I doing wrong in my code?.我在我的代码中做错了什么? Can someone spot what is causing the 2nd (bottom) plot to overwrite the first (top) plot - and how can I fix this?有人可以发现是什么导致第二个(底部)plot 覆盖第一个(顶部)plot - 我该如何解决这个问题?

Here is a screenshot of the plot created by the code above:这是上面代码创建的 plot 的屏幕截图:

错误的情节

[[Edit]] [[编辑]]

After modifying the code as suggested by hwlau, this is the new plot. It is better than the first in that the two plots are separate, however the following issues remain:按照 hwlau 的建议修改代码后,这是新的 plot。它比第一个更好,因为两个图是分开的,但是仍然存在以下问题:

  1. The X axis should be SHARED by the two plots (ie the X axis should be shown only for the 2nd [bottom] plot) X 轴应该由两个图共享(即 X 轴应该只显示第二个 [底部] 图)

  2. The Y values for the 2nd plot seem to be formmated incorrectly第二个 plot 的 Y 值似乎格式不正确

部分正确的情节

I think these issues should be quite easy to resolve however, my matplotlib fu is not great at the moment, as I have only recently started programming with matplotlib. any help will be much appreciated.我认为这些问题应该很容易解决,但是,我的 matplotlib fu 目前不是很好,因为我最近才开始使用 matplotlib 进行编程。任何帮助将不胜感激。

There seem to be a couple of problems with your code:您的代码似乎有几个问题:

  1. If you were using figure.add_subplots with the full signature of subplot(nrows, ncols, plotNum) it may have been more apparent that your first plot asking for 1 row and 1 column and the second plot was asking for 2 rows and 1 column.如果您使用的figure.add_subplots具有 subplot subplot(nrows, ncols, plotNum)的完整签名,则可能更明显的是您的第一个 plot 要求 1 行和 1 列,第二个 plot 要求 2 行和 1 列。 Hence your first plot is filling the whole figure.因此,您的第一个 plot 填满了整个数字。 Rather than fig.add_subplot(111) followed by fig.add_subplot(212) use fig.add_subplot(211) followed by fig.add_subplot(212) .而不是fig.add_subplot(111)后跟fig.add_subplot(212)使用fig.add_subplot(211)后跟fig.add_subplot(212)

  2. Sharing an axis should be done in the add_subplot command using sharex=first_axis_instance共享轴应该在add_subplot命令中使用sharex=first_axis_instance

I have put together an example which you should be able to run:我整理了一个您应该能够运行的示例:

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

Hope that helps.希望有所帮助。

You should change this line:你应该改变这一行:

ax = fig.add_subplot(111)

to

ax = fig.add_subplot(211)

The original command means that there is one row and one column so it occupies the whole graph.原来的命令是一行一列,所以它占据了整个图。 So your second graph fig.add_subplot(212) cover the lower part of the first graph.所以你的第二张图 fig.add_subplot(212) 覆盖了第一张图的下部。

Edit编辑

If you dont want the gap between two plots, use subplots_adjust() to change the size of the subplots margin.如果您不希望两个图之间存在间隙,请使用 subplots_adjust() 更改子图边距的大小。

The example from @Pelson, simplified.来自@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()

The subplots sharing an x-axis are created in one line, which is convenient when you want more than two subplots:共享 x 轴的子图在一行中创建,当您需要两个以上的子图时,这很方便:

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

To format the date correctly on the x axis, we can simply use fig.autofmt_xdate()要在 x 轴上正确格式化日期,我们可以简单地使用fig.autofmt_xdate()

共享 x x 轴

For additional informations, see shared axis demo and date demo from the pylab examples.有关其他信息,请参阅 pylab 示例中的共享轴演示日期演示 This example ran on Python3, matplotlib 1.5.1本例运行于Python3,matplotlib 1.5.1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM