2015-04-05 24 views
8

Vorrei tracciare solo una parte dell'array, riparando x parte, ma lasciando la parte in scala automatica. Ho provato come mostrato di seguito, ma non funziona.Matplotlib - fissaggio scala asse xe scala automatica asse y

Qualche suggerimento?

import numpy as np 
import matplotlib.pyplot as plt 

data=[np.arange(0,101,1),300-0.1*np.arange(0,101,1)] 

plt.figure() 

plt.scatter(data[0], data[1]) 
plt.xlim([50,100]) 
plt.autoscale(enable=True, axis='y') 

plt.show() 

risposta

5

Autoscaling utilizza sempre l'intera gamma dei dati, così l'asse y è scalato dalla piena portata dei dati y, non solo quello che sta entro i limiti x.

Se vuoi per visualizzare un sottoinsieme dei dati, allora è probabilmente più facile da tracciare solo quel sottoinsieme:

import numpy as np 
import matplotlib.pyplot as plt 

x, y = np.arange(0,101,1) ,300 - 0.1*np.arange(0,101,1) 
mask = (x >= 50) & (x <= 100) 

fig, ax = plt.subplots() 
ax.scatter(x[mask], y[mask]) 

plt.show() 
+0

Ho anche avuto questa idea, ma non sapevo che fare sottoinsieme era così semplice in Python :) – Pygmalion

8

Mentre Joe Kington certamente propone la risposta più sensata quando si raccomanda che solo i dati necessari essere tracciati, ci sono situazioni in cui sarebbe meglio tracciare tutti i dati e solo zoomare su una certa sezione. Inoltre, sarebbe bello avere una funzione "autoscale_y" che richiede solo l'oggetto axes (ad esempio, a differenza della risposta here, che richiede l'uso diretto dei dati.)

Ecco una funzione che consente solo di ridimensionare la y- asse sulla base dei dati che si trova nel visibile x-regione:

def autoscale_y(ax,margin=0.1): 
    """This function rescales the y-axis based on the data that is visible given the current xlim of the axis. 
    ax -- a matplotlib axes object 
    margin -- the fraction of the total height of the y-data to pad the upper and lower ylims""" 

    import numpy as np 

    def get_bottom_top(line): 
     xd = line.get_xdata() 
     yd = line.get_ydata() 
     lo,hi = ax.get_xlim() 
     y_displayed = yd[((xd>lo) & (xd<hi))] 
     h = np.max(y_displayed) - np.min(y_displayed) 
     bot = np.min(y_displayed)-margin*h 
     top = np.max(y_displayed)+margin*h 
     return bot,top 

    lines = ax.get_lines() 
    bot,top = np.inf, -np.inf 

    for line in lines: 
     new_bot, new_top = get_bottom_top(line) 
     if new_bot < bot: bot = new_bot 
     if new_top > top: top = new_top 

    ax.set_ylim(bot,top) 

questo è qualcosa di un hack, e probabilmente non funzionerà in molte situazioni, ma per una trama semplice, funziona bene.

Ecco un semplice esempio di utilizzare questa funzione:

import numpy as np 
import matplotlib.pyplot as plt 

x = np.linspace(-100,100,1000) 
y = x**2 + np.cos(x)*100 

fig,axs = plt.subplots(1,2,figsize=(8,5)) 

for ax in axs: 
    ax.plot(x,y) 
    ax.plot(x,y*2) 
    ax.plot(x,y*10) 
    ax.set_xlim(-10,10) 

autoscale_y(axs[1]) 

axs[0].set_title('Rescaled x-axis') 
axs[1].set_title('Rescaled x-axis\nand used "autoscale_y"') 

plt.show() 

enter image description here

+0

Questo è grande, ma fallisce se la trama contiene axhline() s. Proverò a sintonizzarlo perché è esattamente quello che voglio. –

+0

Ho sostituito y_displayed = Km [((xd> = LO) & (xd <= hi))] con se len (XD) == 2 e xd [0] == 0.0 e xd [1] == 1.0: y_displayed = yd # caso speciale per gestire axhline else: y_displayed = yd [((xd> = lo) & (xd <= hi))] –

+0

Sì, è un peccato che non ci sia alcun autoscale_axis, probabilmente potrebbe essere già implementato nel recente aggiornamento di matplotlib. Grazie per il tuo contributo, lo uso e funziona alla grande! Tuttavia, anche quando si desidera tracciare l'intero intervallo di valori e quindi eseguire lo zoom avanti, la soluzione di @Joe Kinton è più semplice tracciando tutto il range sul pannello sinistro e i valori mascherati su quello corretto. – Hugo