Подтвердить что ты не робот

Matplotlib: создание двух (уложенных) подлодок с осью SHARED X, но значения SEPARATE Y

Я использую matplotlib 1.2.x и Python 2.6.5 на Ubuntu 10.0.4. Я пытаюсь создать единый сюжет, состоящий из верхнего сюжета и нижнего участка.

Ось 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 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()

Мне удалось отобразить два графика, используя вышеприведенный код, однако есть две проблемы с нижним графиком:

  • ПОЛНОСТЬЮ ПЕРЕЗАПИСИТ нижнюю часть первого (верхнего) сюжета - почти как если бы второй сюжет рисовал на одном и том же "холсте" в качестве первого сюжета - я не вижу, где/почему это происходит.

  • Он ПЕРЕЗАПИСИВАЕТ существующую ось Х с собственным индексом, значения X-оси (даты) должны быть ОБНАРУЕМЫ между двумя графиками.

Что я делаю неправильно в своем коде?. Может ли кто-то определить, что вызывает второй (нижний) график, чтобы перезаписать первый (верхний) график - и как я могу это исправить?

Вот скриншот сюжета, созданного кодом выше:

faulty plot

[[Edit]]

После изменения кода, предложенного hwlau, это новый график. Это лучше, чем первое из того, что два графика являются отдельными, однако остаются следующие проблемы:

  • Ось X должна быть расширена двумя графиками (то есть ось X должна отображаться только для 2-го [нижнего] графика)

  • Значения Y для 2-го графика кажутся неверно сформированными

partly correct plot

Я думаю, что эти проблемы должны быть довольно легко разрешены, но мой matplotlib fu на данный момент невелик, так как я только недавно начал программировать с помощью matplotlib. любая помощь будет высоко оценена.

4b9b3361

Ответ 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).

  • Совместное использование оси должно выполняться в команде add_subplot с помощью 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()

Надеюсь, что это поможет.

Ответ 2

Вы должны изменить эту строку:

ax = fig.add_subplot(111)

к

ax = fig.add_subplot(211)

Исходная команда означает, что есть одна строка и один столбец, поэтому он занимает весь граф. Таким образом, ваш второй график fig.add_subplot (212) охватывает нижнюю часть первого графика.

Edit

Если вам не нужен разрыв между двумя графиками, используйте subplots_adjust(), чтобы изменить размер поля подзаголовков.

Ответ 3

Пример из @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. Этот пример выполнялся на Python3, matplotlib 1.5.1