2015-11-10 63 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