2015-11-10 88 views
1

我從these two posts on SO獲取了大量關於在matplotlib中將曲線填充到曲線下方的信息。我嘗試了在一個座標軸上繪製多個繪圖的同樣的事情,並且處理它們的順序和它們的alpha以確保它們可見。我得到PIL的錯誤,輸出這個圖的代碼:enter image description hereMatplotlib圖形中的漸變填充

是否有可能使plot下面的'fill'進一步下降,並修復右下角的錯誤?我通過將原始數據放在bpaste上包含了我在這個例子中使用的數據,所以即使很長時間,這個例子也是完全獨立的。

它可能與後端使用有關嗎?

感謝,賈裏德

import pandas as pd 
import matplotlib.pyplot as plt 
import matplotlib.colors as mcolors 
from matplotlib.patches import Polygon 
from matplotlib.ticker import Formatter, FuncFormatter 
import matplotlib 
import numpy as np 
from PIL import Image 
from PIL import ImageDraw 
from PIL import ImageFilter 


df = pd.read_csv('https://bpaste.net/raw/87cbf69259ae') 
df = df.set_index('Date', drop=True) 
df.index = pd.to_datetime(df.index) 


df1 = pd.read_csv('https://bpaste.net/raw/bc06b26b0b8b') 
df1 = df1.set_index('Date', drop=True) 
df1.index = pd.to_datetime(df1.index) 

def zfunc(x, y, fill_color='k', alpha=1.0, xmin=None, xmax=None, ymin=None, ymax=None): 

    if xmax is not None: 
     xmax = int(xmax) 

    if xmin is not None: 
     xmin = int(xmin) 

    if ymax is not None: 
     ymax = int(ymax) 

    if ymin is not None: 
     ymin = int(ymin) 

    w, h = xmax-xmin, ymax-ymin 
    z = np.empty((h, w, 4), dtype=float) 
    rgb = mcolors.colorConverter.to_rgb(fill_color) 
    z[:,:,:3] = rgb 

    # Build a z-alpha array which is 1 near the line and 0 at the bottom. 
    img = Image.new('L', (w, h), 0) 
    draw = ImageDraw.Draw(img) 

    xy = (np.column_stack([x, y])) 
    xy -= xmin, ymin 

    # Draw a blurred line using PIL 
    draw.line(map(tuple, xy.tolist()), fill=255, width=15) 
    img = img.filter(ImageFilter.GaussianBlur(radius=25)) 

    # Convert the PIL image to an array 
    zalpha = np.asarray(img).astype(float) 
    zalpha *= alpha/zalpha.max() 

    # make the alphas melt to zero at the bottom 
    n = int(zalpha.shape[0]/4) 

    zalpha[:n] *= np.linspace(0, 10, n)[:, None] 
    z[:,:,-1] = zalpha 
    return z 


def gradient_fill(x, y, fill_color=None, ax=None, ylabel=None, zfunc=None, **kwargs): 

    if ax is None: 
     ax = plt.gca() 

    if ylabel is not None: 
     ax.set_ylabel(ylabel, weight='bold', color='white') 

    class DateFormatter(Formatter): 
     def __init__(self, dates, fmt='%b \'%y'): 
      self.dates = dates 
      self.fmt = fmt 

     def __call__(self, x, pos=0): 
      'Return the label for time x at position pos' 
      ind = int(round(x)) 
      if ind>=len(self.dates) or ind<0: return '' 

      return self.dates[ind].strftime(self.fmt) 

    def millions(x, pos): 
     return '$%d' % x 

    dollar_formatter = FuncFormatter(millions)  
    formatter = DateFormatter(df.index) 
    ax.yaxis.grid(linestyle='-', alpha=0.5, color='white', zorder=-1) 

    line, = ax.plot(x, y, linewidth=2.0, c=fill_color, **kwargs) 

    if fill_color is None: 
     fill_color = line.get_color() 

    zorder = line.get_zorder() 
    if 'alpha' in kwargs: 
     alpha = kwargs['alpha'] 
    else: 
     alpha = line.get_alpha() 
     alpha = 1.0 if alpha is None else alpha 

    xmin, xmax, ymin, ymax = x.min(), x.max(), y.min(), y.max() 
    diff = ymax - ymin 
    ymin = ymin - diff*0.15 
    ymax = diff*0.05 + ymax 

    if zfunc is None: 
     ## Grab an array of length (cols,rows,spacing) but don't initialize values 
     z = np.empty((110, 1, 4), dtype=float) 
     ## get color to fill for current axix line 
     rgb = mcolors.colorConverter.to_rgb(fill_color) 
     z[:,:,:3] = rgb 
     z[:,:,-1] = np.linspace(0, alpha, 110)[:,None] 
    else: 
     z = zfunc(x, y, fill_color=fill_color, alpha=alpha, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) 

    im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax], origin='lower', zorder=zorder) 

    xy = np.column_stack([x, y]) 
    xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]]) 
    clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True) 
    ax.add_patch(clip_path) 
    ax.patch.set_facecolor('black') 
    im.set_clip_path(clip_path) 


    ax.xaxis.set_major_formatter(formatter) 
    ax.yaxis.set_major_formatter(dollar_formatter) 

    for tick in ax.get_yticklabels(): 
     tick.set_color('white') 

    for tick in ax.get_xticklabels(): 
     tick.set_color('white') 

    w = 17.5 * 1.5 # approximate size in inches of 1280 
    h = 7.5 * 1.5 # approximate size in inches of 720 
    fig = plt.gcf() 
    fig.set_size_inches(w, h) 
#  fig.autofmt_xdate() 
    plt.rcParams['xtick.major.pad']='20' 
    matplotlib.rcParams['ytick.major.pad']='20' 
    matplotlib.rcParams.update({'font.size': 22}) 

    ax.set_ylim((ymin, ymax)) 
    #ax.autoscale(True) 
    return line, im, ax 

line, im, ax = gradient_fill(np.arange(len(df1.index)), df1['/CL_Close'], fill_color='#fdbf6f', ylabel='Crude Oil', alpha=1.0, zfunc=zfunc) 
ax2 = ax.twinx() 
gradient_fill(np.arange(len(df.index)), df['/ES_Close'], ax=ax2, fill_color='#cab2d6', ylabel='S&P', alpha=0.75, zfunc=zfunc) 
ax2.yaxis.grid(False) 
+0

是第一數據鏈路的工作? – gauteh

+0

它爲我工作,但可能是因爲我是一個人。我會用更長的TTL重新加載另一個。 – Jared

+0

@gauteh我編輯過的數據永遠不會在bpaste上過期。 – Jared

回答

4

問題出在您的zfunc。 你說你想通過將它們與np.linspace(0,10,n)相乘來淡化你的alpha。

嘗試:

zalpha[:n] *= np.linspace(0, 1, n)[:, None] 

那麼它爲我的作品...

+0

是的,我認爲這樣做。如果我現在想延長淡入淡出效果(但仍然保持爲零),我沒有在兩條曲線上看到一致的水平。 [Here](http://i.imgur.com/bP86ZDj.png)是我的圖像輸出 - 橙色看起來很棒,紫色不一致。 – Jared

+1

這可能是因爲你的第二行有'alpha = 0.75'。所以它會褪色得更快。如果添加另一個參數「alpha_min」並將其用作上面的「linspace」的第一個參數,則可以獲得更多控制權。 – thomas

1

它比你採取什麼不同的做法,但也許你可以使用Alpha值這樣使用的圖像以不同的強度和顏色表:

import numpy as np 
import scipy as sc 

import matplotlib.pyplot as plt 

x = np.linspace (0, 10, 100) 
y = .5 * x + 4 

plt.figure() 


yres = 100 
ymax = np.max (y) 
ymin = 0 
yy = np.linspace (ymin, ymax, yres) 

fill_n = 10 

xres = len(x) 

# gradient image 
gI = np.zeros ((yres, xres)) 
for xi,xx in enumerate(x): 
    ym = y[xi] 

    # find elment closest to curve 
    ya = np.argmin (np.abs(yy - ym)) 

    gI[ya-fill_n:ya, xi] = np.linspace (0, 1, fill_n) 

# make alpha cmap out of gray map 
bb = np.linspace (0, 1, fill_n) 
kk = [] 
for b in bb: 
    kk.append ((b, b, b)) 

bb = tuple (kk) 
gr = { 'blue' : bb, 
     'red' : bb, 
     'green': bb, 
     'alpha': bb } 

plt.register_cmap (name = 'GrayAlpha', data = gr) 

gI = np.flipud (gI) 
plt.imshow (gI, vmin = 0, vmax = 1, cmap = 'GrayAlpha', interpolation = 'bicubic') 
plt.show() 

enter image description here