2013-04-03 78 views
4

我遇到了matplotlib和Python相當嚴重的問題。我有一個密集的週期圖數據集並且想要繪製它。問題是,當數據點數多於可以在像素上繪製的數據點時,程序包不會選擇顯示最小值和最大值。這意味着對情節的隨意觀察會導致你得出不正確的結論。matplotlib密集數據集的主要顯示問題

這裏有這樣一個問題的例子:
example

數據集與plot()scatter()重疊繪製。您可以看到,在密集的數據字段中,連接數據的藍線沒有達到實際的峯值,導致人類觀察者在〜2.4處得出的峯值是最大值,而實際上並非如此。

如果放大或強制寬視窗,則顯示正確。 rasterizeaa關鍵字對此問題沒有影響。

有沒有辦法確保始終呈現plot()調用的最大/最小點?否則,這需要在對matplotlib的更新中解決。我從來沒有一個陰謀包的行爲是這樣的,這是一個非常重要的問題。

編輯:

x = numpy.linspace(0,1,2000000) 
y = numpy.random.random(x.shape) 
y[1000000]=2 

plot(x,y) 
show() 

應該複製的問題。儘管它可能取決於您的顯示器分辨率。通過拖動和調整窗口大小,您應該看到問題。一個數據點應該突出顯示y = 2,但並不總是顯示。

+2

您正在使用什麼版本MPL的?如果它是最新的,你應該在github跟蹤器上創建一個問題(這將確保這個問題得到核心開發者的關注)。您可以發表一個您用於生成該圖表的示例數據集+代碼嗎?它使測試變得更容易。 – tacaswell 2013-04-03 19:45:46

+2

如果您使用'plot(...,marker ='。',linestyle =' - ')'它是否正確地達到了最小/最大值? – tacaswell 2013-04-03 20:06:21

+0

@tcaswell添加代碼。標記和線型更改沒有幫助。謝謝。 – Doug 2013-04-03 23:26:01

回答

4

這是由於matplotlib中的路徑簡化算法。雖然在某些情況下它確實不可取,但這是故意加快渲染的行爲。

爲了避免跳過「異常點」,簡化算法在某些時候發生了變化,因此mpl的較新版本沒有表現出這種確切的行爲(儘管路徑仍然是簡化的)。

如果您不想簡化路徑,那麼您可以在rc參數中(在您的.matplotlibrc文件中或在運行時)禁用它。

E.g.

import matplotlib as mpl 
mpl.rcParams['path.simplify'] = False 
import matplotlib.pyplot as plt 

但是,使用「envelope」樣式圖可能更有意義。作爲一個簡單的例子:

import matplotlib.pyplot as plt 
import numpy as np 

def main(): 
    num = 10000 
    x = np.linspace(0, 10, num) 
    y = np.cos(x) + 5 * np.random.random(num) 

    fig, (ax1, ax2) = plt.subplots(nrows=2) 
    ax1.plot(x, y) 
    envelope_plot(x, y, winsize=40, ax=ax2) 
    plt.show() 

def envelope_plot(x, y, winsize, ax=None, fill='gray', color='blue'): 
    if ax is None: 
     ax = plt.gca() 
    # Coarsely chunk the data, discarding the last window if it's not evenly 
    # divisible. (Fast and memory-efficient) 
    numwin = x.size // winsize 
    ywin = y[:winsize * numwin].reshape(-1, winsize) 
    xwin = x[:winsize * numwin].reshape(-1, winsize) 
    # Find the min, max, and mean within each window 
    ymin = ywin.min(axis=1) 
    ymax = ywin.max(axis=1) 
    ymean = ywin.mean(axis=1) 
    xmean = xwin.mean(axis=1) 

    fill_artist = ax.fill_between(xmean, ymin, ymax, color=fill, 
            edgecolor='none', alpha=0.5) 
    line, = ax.plot(xmean, ymean, color=color, linestyle='-') 
    return fill_artist, line 

if __name__ == '__main__': 
    main() 

enter image description here