matplotlib: оверлейные графики с разными масштабами? - PullRequest
44 голосов
/ 12 октября 2011

Пока у меня есть следующий код:

colors = ('k','r','b')
ax = []
for i in range(3):
    ax.append(plt.axes())
    plt.plot(datamatrix[:,0],datamatrix[:,i],colors[i]+'o')
    ax[i].set(autoscale_on=True)

С опцией autoscale_on=True для каждой оси я думал, что каждый график должен иметь свои собственные пределы оси Y, но, похоже, все они разделяютодинаковое значение (даже если они имеют разные оси).Как мне установить их масштабирование, чтобы показать диапазон каждого datamatrix[:,i] (просто явный вызов .set_ylim()?) А также, как я могу создать смещение по оси Y для третьей переменной (datamatrix[:,2]), которая можетпотребоваться выше?Спасибо всем.

Ответы [ 3 ]

104 голосов
/ 12 октября 2011

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

Попробуйте что-то еще подобное:

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=3)

colors = ('k', 'r', 'b')
for ax, color in zip(axes, colors):
    data = np.random.random(1) * np.random.random(10)
    ax.plot(data, marker='o', linestyle='none', color=color)

plt.show()

enter image description here

Edit:

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

Вы пытаетесь добавить три оси прямо друг на друга. Matplotlib осознает, что уже есть подзаговор с таким же размером и расположением на фигуре, и поэтому каждый раз возвращает объект одного и того же . Другими словами, если вы посмотрите на свой список ax, вы увидите, что все они один и тот же объект .

Если вы действительно хотите это сделать, вам нужно будет сбрасывать fig._seen на пустой дикт каждый раз, когда вы добавляете оси. Вы, вероятно, на самом деле не хотите этого делать.

Вместо того, чтобы ставить три независимых графика друг на друга, взгляните на использование twinx.

Е.Г.

import matplotlib.pyplot as plt
import numpy as np
# To make things reproducible...
np.random.seed(1977)

fig, ax = plt.subplots()

# Twin the x-axis twice to make independent y-axes.
axes = [ax, ax.twinx(), ax.twinx()]

# Make some space on the right side for the extra y-axis.
fig.subplots_adjust(right=0.75)

# Move the last y-axis spine over to the right by 20% of the width of the axes
axes[-1].spines['right'].set_position(('axes', 1.2))

# To make the border of the right-most axis visible, we need to turn the frame
# on. This hides the other plots, however, so we need to turn its fill off.
axes[-1].set_frame_on(True)
axes[-1].patch.set_visible(False)

# And finally we get to plot things...
colors = ('Green', 'Red', 'Blue')
for ax, color in zip(axes, colors):
    data = np.random.random(1) * np.random.random(10)
    ax.plot(data, marker='o', linestyle='none', color=color)
    ax.set_ylabel('%s Thing' % color, color=color)
    ax.tick_params(axis='y', colors=color)
axes[0].set_xlabel('X-axis')

plt.show()

enter image description here

8 голосов
/ 15 января 2015

Начальная загрузка что-то быстрое для построения диаграммы нескольких осей Y, совместно использующих ось X, используя ответ @ joe-kington * : enter image description here

# d = Pandas Dataframe, 
# ys = [ [cols in the same y], [cols in the same y], [cols in the same y], .. ] 
def chart(d,ys):

    from itertools import cycle
    fig, ax = plt.subplots()

    axes = [ax]
    for y in ys[1:]:
        # Twin the x-axis twice to make independent y-axes.
        axes.append(ax.twinx())

    extra_ys =  len(axes[2:])

    # Make some space on the right side for the extra y-axes.
    if extra_ys>0:
        temp = 0.85
        if extra_ys<=2:
            temp = 0.75
        elif extra_ys<=4:
            temp = 0.6
        if extra_ys>5:
            print 'you are being ridiculous'
        fig.subplots_adjust(right=temp)
        right_additive = (0.98-temp)/float(extra_ys)
    # Move the last y-axis spine over to the right by x% of the width of the axes
    i = 1.
    for ax in axes[2:]:
        ax.spines['right'].set_position(('axes', 1.+right_additive*i))
        ax.set_frame_on(True)
        ax.patch.set_visible(False)
        ax.yaxis.set_major_formatter(matplotlib.ticker.OldScalarFormatter())
        i +=1.
    # To make the border of the right-most axis visible, we need to turn the frame
    # on. This hides the other plots, however, so we need to turn its fill off.

    cols = []
    lines = []
    line_styles = cycle(['-','-','-', '--', '-.', ':', '.', ',', 'o', 'v', '^', '<', '>',
               '1', '2', '3', '4', 's', 'p', '*', 'h', 'H', '+', 'x', 'D', 'd', '|', '_'])
    colors = cycle(matplotlib.rcParams['axes.color_cycle'])
    for ax,y in zip(axes,ys):
        ls=line_styles.next()
        if len(y)==1:
            col = y[0]
            cols.append(col)
            color = colors.next()
            lines.append(ax.plot(d[col],linestyle =ls,label = col,color=color))
            ax.set_ylabel(col,color=color)
            #ax.tick_params(axis='y', colors=color)
            ax.spines['right'].set_color(color)
        else:
            for col in y:
                color = colors.next()
                lines.append(ax.plot(d[col],linestyle =ls,label = col,color=color))
                cols.append(col)
            ax.set_ylabel(', '.join(y))
            #ax.tick_params(axis='y')
    axes[0].set_xlabel(d.index.name)
    lns = lines[0]
    for l in lines[1:]:
        lns +=l
    labs = [l.get_label() for l in lns]
    axes[0].legend(lns, labs, loc=0)

    plt.show()
5 голосов
/ 08 августа 2016

Благодаря ответу Джо Кингтона я смог найти решение для моего требования, чтобы все дополнительные оси Y находились в левой части графика.

Я все еще хотел бы знать, как сделать это правильно, потому что это всего лишь обходной путь:

import matplotlib.pyplot as plt
import numpy as np
# To make things reproducible...
np.random.seed(1977)

fig, ax = plt.subplots()

# Twin the x-axis twice to make independent y-axes.
axes = [ax, ax.twinx(), ax.twinx()]

# Make some space on the right side for the extra y-axis.
fig.subplots_adjust(right=0.75)

# Move the last y-axis spine over to the right by 20% of the width of the axes
axes[1].spines['right'].set_position(('axes', -0.25))
axes[2].spines['right'].set_position(('axes', -0.5))

# To make the border of the right-most axis visible, we need to turn the frame
# on. This hides the other plots, however, so we need to turn its fill off.
axes[-1].set_frame_on(True)
axes[-1].patch.set_visible(False)

# And finally we get to plot things...
colors = ('Green', 'Red', 'Blue')
intAxNo = 0
for ax, color in zip(axes, colors):
    intAxNo += 1
    data = np.random.random(1) * np.random.random(10)
    ax.plot(data, marker='o', linestyle='none', color=color)
    if (intAxNo > 1):
        if (intAxNo == 2):
            ax.set_ylabel('%s Thing' % color, color=color, labelpad = -40 )
        elif (intAxNo == 3):
            ax.set_ylabel('%s Thing' % color, color=color, labelpad = -45 )
        ax.get_yaxis().set_tick_params(direction='out')
    else:
        ax.set_ylabel('%s Thing' % color, color=color, labelpad = +0 )

    ax.tick_params(axis='y', colors=color)
axes[0].set_xlabel('X-axis')


plt.show()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...