2012-02-01 20 views
50

In che modo è possibile implementare più bilance in Matplotlib? Non sto parlando dell'asse primario e secondario tracciato contro lo stesso asse x, ma qualcosa come molte tendenze che hanno diverse scale tracciate nello stesso asse y e che possono essere identificate dai loro colori.asse multiplo in matplotlib con diverse scale

Per esempio, se ho trend1 ([0,1,2,3,4]) e trend2 ([5000,6000,7000,8000,9000]) per essere rilevata in tempo e voglio che le due tendenze di essere di diversi colori e in asse Y, scale differenti, come posso fare questo con Matplotlib?

Quando ho guardato in Matplotlib, dicono che per ora non ce l'hanno, anche se è sicuramente sulla loro lista dei desideri, c'è un modo per farlo accadere?

Esistono altri strumenti di tracciamento per Python che possono rendere questo possibile?

+5

Questo risponde alla tua domanda: http://stackoverflow.com/questions/7733693/matplotlib-overlay-plots-with-different-scales – Yann

+0

Le risposte a http: // stackoverflow.com/questions/5484922/secondary-axis-with-twinx-how-to-add-to-legend forniscono esempi. –

risposta

78

Se ho compreso la domanda, è possibile che sia interessato a this example nella galleria Matplotlib.

enter image description here

commento di Yann fornisce sopra un esempio simile.


Modifica - Collegamento sopra fisso. Corrispondente codice copiato dalla galleria 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") 
+0

Grazie! Era quello che stavo cercando ... –

+3

-1 perché le risposte nascoste dietro i collegamenti sono meno utili e tendono a marcire. – dlras2

+0

Verità. Collegamento interrotto. – nathancahill

36

se si vuole fare trame molto rapidi con secondario asse Y allora non c'è modo molto più semplice utilizzando la funzione wrapper di Panda e solo 2 righe di codice. Basta tracciare la vostra prima colonna poi tracciare la seconda, ma con il parametro secondary_y=True, in questo modo:

Questo sarebbe simile di seguito:

enter image description here

Si possono fare alcune cose pure. Dai un'occhiata a Pandas plotting doc.

+0

secondary_y = True did it – Ivelin

+0

Suggerimento brillante, grazie – ruX

16

bootstrap qualcosa di veloce di tracciare molteplici assi Y condividono un asse x utilizzando @joe-kington's risposta: 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() 
+0

Impressionante, funziona come un incantesimo! Grazie! – Svend

+0

In questo esempio, gli assi di destra sono tutti lineari, il che non è sempre il caso nella pratica. Se dovessi dimostrare una dipendenza arbitraria non lineare tra gli assi y di sinistra e di destra, e vorresti mantenere dei bei numeri rotondi su entrambi, ecco una soluzione: https://github.com/matplotlib/matplotlib/issues/7161 # issuecomment-249611750 – dominecf

13

Dal Steve Tjoa's answer schiocca sempre per primo e per lo più solo quando cerco per più assi Y su Google, ho deciso di aggiungere una versione leggermente modificata della sua risposta.

Motivi:

  • suoi moduli a volte non riescono per me in circostanze sconosciute ed errori intern criptici.
  • Non mi piace caricare moduli esotici che non conosco (mpl_toolkits.axisartist, mpl_toolkits.axes_grid1).
  • Il codice seguente contiene più espliciti comandi di problemi che spesso le persone inciampano (come una singola legenda per più assi, utilizzando viridis, ...) piuttosto che un comportamento implicito.

Plot

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') 
+2

+1 per una versione che consente l'uso del modulo matplotlib standard. Vorrei anche indirizzare gli utenti correnti verso l'uso del moderno, più coraziale metodo "subplots()' come evidenziato [qui] (https://matplotlib.org/users/recipes.html) e come pure jarondl esorta [qui] (https://stackoverflow.com/questions/3584805/in-matplotlib-what-does-the-argument-mean-in-fig-add-subplot111#comment18305007_3584933). Fortunatamente, funziona con questa risposta. Devi solo sostituire le due righe dopo l'importazione con 'fig, host = plt.subplots (nrows = 1, ncols = 1)'. – Wayne

+2

Ho anche notato che questa risposta consente ancora l'applicazione della [soluzione Rutger Kassies] (https://stackoverflow.com/a/20147135/8508004) per spostare l'asse secondario (a.k.a asse parassita) sul lato sinistro. In questo codice, per farlo sostituirai 'par2.spines ['right']. Set_position (('outward', 60))' con le seguenti ** quattro ** righe: 'par2.spines [' left ']. set_position ((' outward ', 60)) ' ' par2.spines ["left"]. set_visible (True) ' ' par2.yaxis.set_label_position (' left ') ' ' par2.yaxis. set_ticks_position ('left') ' – Wayne

Problemi correlati