plusieurs axes dans matplotlib avec différentes échelles

Comment plusieurs échelles peuvent-elles être implémentées dans Matplotlib? Je ne parle pas des axes primaire et secondaire tracés contre le même axe x, mais quelque chose comme beaucoup de tendances qui ont des échelles différentes tracées dans le même axe y et qui peuvent être identifiées par leurs couleurs.

Par exemple, si j'ai trend1 ([0,1,2,3,4]) et trend2 ([5000,6000,7000,8000,9000]) à tracer dans le temps et que je veux que les deux tendances soient de couleurs différentes et dans l'axe des Y, des échelles différentes, Comment puis-je accomplir cela avec Matplotlib?

Quand J'ai regardé dans Matplotlib, ils disent qu'ils ne l'ont pas pour l'instant bien qu'il soit définitivement sur leur liste de souhaits, y a-t-il un moyen de faire en sorte que cela se produise?

Existe-t-il d'autres outils de traçage pour python qui peuvent y arriver?

57
demandé sur naught101 2012-02-02 00:50:14

4 réponses

Si je comprends la question, vous pouvez vous intéresser à cet exemple dans la galerie Matplotlib.

entrez la description de l'image ici

Le Commentaire de Yann ci-dessus fournit un exemple similaire.


Modifier-lien ci-dessus fixe. Code correspondant copié à partir de la galerie Matplotlib:

from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
import matplotlib.pyplot as plt

host = host_subplot(111, axes_class=AA.Axes)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

offset = 60
new_fixed_axis = par2.get_grid_helper().new_fixed_axis
par2.axis["right"] = new_fixed_axis(loc="right", axes=par2,
                                        offset=(offset, 0))

par2.axis["right"].toggle(all=True)

host.set_xlim(0, 2)
host.set_ylim(0, 2)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.legend()

host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())

plt.draw()
plt.show()

#plt.savefig("Test")
81
répondu Steve Tjoa 2017-05-31 13:21:01

Si vous voulez faire des tracés très rapides avec l'axe Y secondaire, il est beaucoup plus facile d'utiliser la fonction Pandas wrapper et seulement 2 lignes de code. Tracez simplement votre première colonne puis tracez la seconde mais avec le paramètre secondary_y=True, comme ceci:

df.A.plot(label="Points", legend=True)
df.B.plot(secondary_y=True, label="Comments", legend=True)

Cela ressemblerait à quelque chose comme ci-dessous:

entrez la description de l'image ici

Vous pouvez aussi faire peu de choses. Jetez un oeil à Pandas traçant doc .

39
répondu ShitalShah 2014-07-03 00:38:43

Depuis la réponse de Steve Tjoa apparaît toujours en premier et surtout solitaire Quand je recherche plusieurs axes y chez Google, j'ai décidé d'ajouter une version légèrement modifiée de sa réponse. C'est l'approche de cet exemple matplotlib .

Raisons:

  • ses modules échouent parfois pour moi dans des circonstances inconnues et des erreurs internes cryptiques.
  • Je n'aime pas charger des modules exotiques Je ne sais pas (mpl_toolkits.axisartist, mpl_toolkits.axes_grid1).
  • le code ci-dessous contient plus commandes explicites des problèmes que les gens trébuchent souvent (comme une seule légende pour plusieurs axes, en utilisant viridis,...) plutôt qu'un comportement implicite.

Parcelle

import matplotlib.pyplot as plt 

fig = plt.figure()
host = fig.add_subplot(111)

par1 = host.twinx()
par2 = host.twinx()

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

color1 = plt.cm.viridis(0)
color2 = plt.cm.viridis(0.5)
color3 = plt.cm.viridis(.9)

p1, = host.plot([0, 1, 2], [0, 1, 2], color=color1,label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], color=color2, label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], color=color3, label="Velocity")

lns = [p1, p2, p3]
host.legend(handles=lns, loc='best')

# right, left, top, bottom
par2.spines['right'].set_position(('outward', 60))      
# no x-ticks                 
par2.xaxis.set_ticks([])
# Sometimes handy, same for xaxis
#par2.yaxis.set_ticks_position('right')

host.yaxis.label.set_color(p1.get_color())
par1.yaxis.label.set_color(p2.get_color())
par2.yaxis.label.set_color(p3.get_color())

plt.savefig("pyplot_multiple_y-axis.png", bbox_inches='tight')
28
répondu Suuuehgi 2018-05-30 08:28:46

Bootstrapping quelque chose de rapide pour tracer plusieurs axes y partageant un axe x en utilisant @ joe-kington's Réponse: entrez la description de l'image ici

# 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()
17
répondu Nasser Al-Wohaibi 2017-05-23 12:18:10