Matplotlib 要从遮罩阵列平滑轮廓吗

Matplotlib 要从遮罩阵列平滑轮廓吗,matplotlib,scipy,contour,Matplotlib,Scipy,Contour,我有一个蒙版数组,matplotlib.plt.contourf使用它在glabal地图上投影温度等值线。我试图平滑轮廓,但不幸的是,提出的解决方案似乎都无法处理遮罩阵列。我测试了这些解决方案: - scipy.ndimage.zoom 它们都不起作用(它们也计入屏蔽值)。有没有办法让我的轮廓在面具上平滑 我在尝试了建议的“修复”解决方案后添加了这一部分,结果没有改变。下面是代码(如果有帮助的话) 我将此代码的输出(第一个图)与Panoply相同数据文件的输出进行比较。放大并更精确地查看似

我有一个蒙版数组,matplotlib.plt.contourf使用它在glabal地图上投影温度等值线。我试图平滑轮廓,但不幸的是,提出的解决方案似乎都无法处理遮罩阵列。我测试了这些解决方案:

-

  • scipy.ndimage.zoom
它们都不起作用(它们也计入屏蔽值)。有没有办法让我的轮廓在面具上平滑


我在尝试了建议的“修复”解决方案后添加了这一部分,结果没有改变。下面是代码(如果有帮助的话)

我将此代码的输出(第一个图)与Panoply相同数据文件的输出进行比较。放大并更精确地查看似乎不是平滑度问题,但pyplot模型提供了一条更细的条纹,或者轮廓被更早地切割(外部边界清楚地显示了这一点,而内部轮廓因此而不同)。这使得pyplot模型看起来不像Panoply模型那样平滑。我怎样才能得到(几乎)相同的型号?我区分对了吗


我也有类似的问题,谷歌给我指出了这一点:。基本上,他使用修复算法来插值缺失值,并生成有效的过滤数组

代码位于文章的末尾,您可以将其保存到站点包(或其他)并作为模块加载(即
inpaint.py
):

我对结果很满意,我想它可以很好地拟合缺失的温度值。这里还有下一个版本:但由于代码是项目的一部分,因此需要对其进行一些清理,以供一般使用

为了便于参考、使用和保存,我将在此处发布代码(初始版本):

#-*-编码:utf-8-*-
“”“用于各种实用程序和帮助程序功能的模块”“”
将numpy作为np导入
#cimport numpy作为np
#西姆波特赛顿酒店
DTYPEf=np.64
#ctypedef np.float64\u t DTYPEf\t
DTYPEi=np.int32
#ctypedef np.int32\u t数据类型
#@cython.boundscheck(False)#对整个函数进行边界检查
#@cython.wrapparound(False)#对整个函数进行边界检查
def replace_nans(数组、最大iter、tol、内核大小=1,method='localmean'):
“”“使用迭代图像修复算法替换数组中的NaN元素。”。
算法如下所示:
1) 对于输入数组中的每个元素,将其替换为加权平均值
不是NaN本身的相邻元素。权重取决于
如果``method=localmean``权重等于1/((2*kernel\u size+1)**2-1)
2) 如果存在相邻的NaN元素,则需要多次迭代。
如果是这种情况,则信息将从缺失区域的边缘“传播”
迭代区域,直到变化低于某个阈值。
参数
----------
数组:2d np.ndarray
包含必须替换的NaN元素的数组
最大值:整数
迭代次数
内核大小:int
内核的大小,默认值为1
方法:str
用于替换无效值的方法。有效选项包括
`localmean`,'idw'。
退换商品
-------
填充:2d np.N阵列
已替换NaN元素的输入数组的副本。
"""
#cdef int i,j,i,j,it,n,k,l
#残疾人士国际中心
filled=np.empty([array.shape[0],array.shape[1]],dtype=DTYPEf)
kernel=np.empty((2*kernel\u size+1,2*kernel\u size+1),dtype=DTYPEf)
#cdef np.ndarray[np.int_t,ndim=1]
#cdef np.ndarray[np.int_t,ndim=1]jnans
#数组为NaN的索引
inans,jnans=np.nonzero(np.isnan(数组))
#NaN元素数
n_nans=len(inans)
#包含替换值以检查收敛性的数组
替换为新的=np.0(n n n,dtype=DTYPEf)
替换旧的=np.0(n n n n,dtype=DTYPEf)
#根据内核类型,填充内核数组
如果方法=='localmean':
打印“内核大小”,内核大小
对于范围内的i(2*内核大小+1):
对于范围内的j(2*内核大小+1):
核[i,j]=1
打印内核,“内核”
elif方法=='idw':
kernel=np.array([[0,0.5,0.5,0.5,0],
[0.5,0.75,0.75,0.75,0.5], 
[0.5,0.75,1,0.75,0.5],
[0.5,0.75,0.75,0.5,1],
[0, 0.5, 0.5 ,0.5 ,0]])
打印内核,“内核”
其他:
raise ValueError('方法无效。应为'localmean'之一)
#用输入元素填充新数组
对于范围内的i(array.shape[0]):
对于范围内的j(array.shape[1]):
填充的[i,j]=数组[i,j]
#多次通过
#直到我们达到一致
对于范围内的it(最大值):
打印“迭代”,它
#对于每个NaN元素
对于范围内的k(n_南):
i=inans[k]
j=jnans[k]
#初始化为零
填充[i,j]=0.0
n=0
#在内核上循环
对于范围内的I(2*内核大小+1):
对于范围内的J(2*内核大小+1):
#如果我们不在边界之外
如果i+i-kernel\u size=0:
如果j+j-kernel\u size=0:
#如果相邻元素本身不是NaN。
如果已填充[i+i-内核大小,j+j-内核大小]==已填充[i+i-内核大小,j+j-内核大小]:
#不要自我总结
如果I-kernel_size!=0和J内核大小!=0:
#原始数组的卷积核
填充的[i,j]=填充的[i,j]+填充的[i+i-内核大小,j+j-内核大小]*内核[i,j]
n=n+1*内核[I,J]
#将值除以添加元素的有效数量
如果n!=0:
填充[i,j]
import Scientific.IO.NetCDF as S
import mpl_toolkits.basemap as bm
import numpy.ma as MA
import numpy as np
import matplotlib.pyplot as plt
import inpaint

def main():

    fileobj = S.NetCDFFile('Bias.ANN.tas_A1_1.nc', mode='r')

    # take the values
    set1 = {'time', 'lat', 'lon'}
    set2 = set(fileobj.variables.keys())
    set3 = set2 - set1
    datadim = set3.pop()
    print "******************datadim: "+datadim
    data = fileobj.variables[datadim].getValue()[0,:,:]


    lon = fileobj.variables['lon'].getValue()
    lat = fileobj.variables['lat'].getValue()
    fileobj.close()


    data, lon = bm.shiftgrid(180.,data, lon,start=False)
    data = MA.masked_equal(data, 1.0e20)
    #data2 = inpaint.replace_nans(data, 10, 0.25, 2, 'idw')
    #- Make 2-D longitude and latitude arrays:

    [lon2d, lat2d] =np.meshgrid(lon, lat)


    #- Set up map:

    mapproj = bm.Basemap(projection='cyl', 
                       llcrnrlat=-90.0, llcrnrlon=-180.00,
                       urcrnrlat=90.0, urcrnrlon=180.0)
    mapproj.drawcoastlines(linewidth=.5)
    mapproj.drawmapboundary(fill_color='.8')
    #mapproj.drawparallels(N.array([-90, -45, 0, 45, 90]), labels=[1,0,0,0])
    #mapproj.drawmeridians(N.array([0, 90, 180, 270, 360]), labels=[0,0,0,1])
    lonall, latall = mapproj(lon2d, lat2d)

    cmap=plt.cm.Spectral
    #- Make a contour plot of the temperature:
    mymapf = plt.contourf(lonall, latall, data, 20, cmap=cmap)
    #plt.clabel(mymapf, fontsize=12)
    plt.title(cmap.name)
    plt.colorbar(mymapf, orientation='horizontal')

    plt.savefig('sample2.png', dpi=150, edgecolor='red', format='png', bbox_inches='tight', pad_inches=.2)
    plt.close()
if __name__ == "__main__":
  main()
import inpaint

filled = inpaint.replace_nans(NANMask, 5, 0.5, 2, 'idw')
# -*- coding: utf-8 -*-

"""A module for various utilities and helper functions"""

import numpy as np
#cimport numpy as np
#cimport cython

DTYPEf = np.float64
#ctypedef np.float64_t DTYPEf_t

DTYPEi = np.int32
#ctypedef np.int32_t DTYPEi_t

#@cython.boundscheck(False) # turn of bounds-checking for entire function
#@cython.wraparound(False) # turn of bounds-checking for entire function
def replace_nans(array, max_iter, tol,kernel_size=1,method='localmean'):
    """Replace NaN elements in an array using an iterative image inpainting algorithm.
The algorithm is the following:
1) For each element in the input array, replace it by a weighted average
of the neighbouring elements which are not NaN themselves. The weights depends
of the method type. If ``method=localmean`` weight are equal to 1/( (2*kernel_size+1)**2 -1 )
2) Several iterations are needed if there are adjacent NaN elements.
If this is the case, information is "spread" from the edges of the missing
regions iteratively, until the variation is below a certain threshold.
Parameters
----------
array : 2d np.ndarray
an array containing NaN elements that have to be replaced
max_iter : int
the number of iterations
kernel_size : int
the size of the kernel, default is 1
method : str
the method used to replace invalid values. Valid options are
`localmean`, 'idw'.
Returns
-------
filled : 2d np.ndarray
a copy of the input array, where NaN elements have been replaced.
"""

#    cdef int i, j, I, J, it, n, k, l
#    cdef int n_invalids

    filled = np.empty( [array.shape[0], array.shape[1]], dtype=DTYPEf)
    kernel = np.empty( (2*kernel_size+1, 2*kernel_size+1), dtype=DTYPEf )

#    cdef np.ndarray[np.int_t, ndim=1] inans
#    cdef np.ndarray[np.int_t, ndim=1] jnans

    # indices where array is NaN
    inans, jnans = np.nonzero( np.isnan(array) )

    # number of NaN elements
    n_nans = len(inans)

    # arrays which contain replaced values to check for convergence
    replaced_new = np.zeros( n_nans, dtype=DTYPEf)
    replaced_old = np.zeros( n_nans, dtype=DTYPEf)

    # depending on kernel type, fill kernel array
    if method == 'localmean':

        print 'kernel_size', kernel_size       
        for i in range(2*kernel_size+1):
            for j in range(2*kernel_size+1):
                kernel[i,j] = 1
        print kernel, 'kernel'

    elif method == 'idw':
        kernel = np.array([[0, 0.5, 0.5, 0.5,0],
                  [0.5,0.75,0.75,0.75,0.5], 
                  [0.5,0.75,1,0.75,0.5],
                  [0.5,0.75,0.75,0.5,1],
                  [0, 0.5, 0.5 ,0.5 ,0]])
        print kernel, 'kernel'      
    else:
        raise ValueError( 'method not valid. Should be one of `localmean`.')

    # fill new array with input elements
    for i in range(array.shape[0]):
        for j in range(array.shape[1]):
            filled[i,j] = array[i,j]

    # make several passes
    # until we reach convergence
    for it in range(max_iter):
        print 'iteration', it
        # for each NaN element
        for k in range(n_nans):
            i = inans[k]
            j = jnans[k]

            # initialize to zero
            filled[i,j] = 0.0
            n = 0

            # loop over the kernel
            for I in range(2*kernel_size+1):
                for J in range(2*kernel_size+1):

                    # if we are not out of the boundaries
                    if i+I-kernel_size < array.shape[0] and i+I-kernel_size >= 0:
                        if j+J-kernel_size < array.shape[1] and j+J-kernel_size >= 0:

                            # if the neighbour element is not NaN itself.
                            if filled[i+I-kernel_size, j+J-kernel_size] == filled[i+I-kernel_size, j+J-kernel_size] :

                                # do not sum itself
                                if I-kernel_size != 0 and J-kernel_size != 0:

                                    # convolve kernel with original array
                                    filled[i,j] = filled[i,j] + filled[i+I-kernel_size, j+J-kernel_size]*kernel[I, J]
                                    n = n + 1*kernel[I,J]

            # divide value by effective number of added elements
            if n != 0:
                filled[i,j] = filled[i,j] / n
                replaced_new[k] = filled[i,j]
            else:
                filled[i,j] = np.nan

        # check if mean square difference between values of replaced
        #elements is below a certain tolerance
        print 'tolerance', np.mean( (replaced_new-replaced_old)**2 )
        if np.mean( (replaced_new-replaced_old)**2 ) < tol:
            break
        else:
            for l in range(n_nans):
                replaced_old[l] = replaced_new[l]

    return filled


def sincinterp(image, x,  y, kernel_size=3 ):
    """Re-sample an image at intermediate positions between pixels.
This function uses a cardinal interpolation formula which limits
the loss of information in the resampling process. It uses a limited
number of neighbouring pixels.
The new image :math:`im^+` at fractional locations :math:`x` and :math:`y` is computed as:
.. math::
im^+(x,y) = \sum_{i=-\mathtt{kernel\_size}}^{i=\mathtt{kernel\_size}} \sum_{j=-\mathtt{kernel\_size}}^{j=\mathtt{kernel\_size}} \mathtt{image}(i,j) sin[\pi(i-\mathtt{x})] sin[\pi(j-\mathtt{y})] / \pi(i-\mathtt{x}) / \pi(j-\mathtt{y})
Parameters
----------
image : np.ndarray, dtype np.int32
the image array.
x : two dimensions np.ndarray of floats
an array containing fractional pixel row
positions at which to interpolate the image
y : two dimensions np.ndarray of floats
an array containing fractional pixel column
positions at which to interpolate the image
kernel_size : int
interpolation is performed over a ``(2*kernel_size+1)*(2*kernel_size+1)``
submatrix in the neighbourhood of each interpolation point.
Returns
-------
im : np.ndarray, dtype np.float64
the interpolated value of ``image`` at the points specified
by ``x`` and ``y``
"""

    # indices
#    cdef int i, j, I, J

    # the output array
    r = np.zeros( [x.shape[0], x.shape[1]], dtype=DTYPEf)

    # fast pi
    pi = 3.1419

    # for each point of the output array
    for I in range(x.shape[0]):
        for J in range(x.shape[1]):

            #loop over all neighbouring grid points
            for i in range( int(x[I,J])-kernel_size, int(x[I,J])+kernel_size+1 ):
                for j in range( int(y[I,J])-kernel_size, int(y[I,J])+kernel_size+1 ):
                    # check that we are in the boundaries
                    if i >= 0 and i <= image.shape[0] and j >= 0 and j <= image.shape[1]:
                        if (i-x[I,J]) == 0.0 and (j-y[I,J]) == 0.0:
                            r[I,J] = r[I,J] + image[i,j]
                        elif (i-x[I,J]) == 0.0:
                            r[I,J] = r[I,J] + image[i,j] * np.sin( pi*(j-y[I,J]) )/( pi*(j-y[I,J]) )
                        elif (j-y[I,J]) == 0.0:
                            r[I,J] = r[I,J] + image[i,j] * np.sin( pi*(i-x[I,J]) )/( pi*(i-x[I,J]) )
                        else:
                            r[I,J] = r[I,J] + image[i,j] * np.sin( pi*(i-x[I,J]) )*np.sin( pi*(j-y[I,J]) )/( pi*pi*(i-x[I,J])*(j-y[I,J]))
    return r


#cdef extern from "math.h":
 #   double sin(double)
from numpy import *
import pylab as plt

#  make a grid and a striped mask as test data
N = 100
x = linspace(0, 5, N, endpoint=True)
grid = 2. + 1.*(sin(2*pi*x)[:,newaxis]*sin(2*pi*x)>0.)
m = resize((sin(pi*x)>0), (N,N))

plt.imshow(grid.copy(), cmap='jet', interpolation='nearest')
plt.colorbar()
plt.title('original data')


def smooth(u, mask):
    m = ~mask
    r = u*m  # set all 'masked' points to 0. so they aren't used in the smoothing
    a = 4*r[1:-1,1:-1] + r[2:,1:-1] + r[:-2,1:-1] + r[1:-1,2:] + r[1:-1,:-2]
    b = 4*m[1:-1,1:-1] + m[2:,1:-1] + m[:-2,1:-1] + m[1:-1,2:] + m[1:-1,:-2]  # a divisor that accounts for masked points
    b[b==0] = 1.  # for avoiding divide by 0 error (region is masked so value doesn't matter)
    u[1:-1,1:-1] = a/b

# run the data through the smoothing filter a few times
for i in range(10):   
    smooth(grid, m)

mg = ma.array(grid, mask=m)  # put together the mask and the data

plt.figure()
plt.imshow(mg, cmap='jet', interpolation='nearest')
plt.colorbar()
plt.title('smoothed with mask')

plt.show()
import numpy as np
import matplotlib.pyplot as plt

# Some Axes
x = np.arange(100)
y = np.arange(100)
#Some Interesting Shape
z = np.array(np.outer(np.sin((x+y)/10),np.sin(y/3)),dtype=float)

# some mask
mask = np.outer(np.sin((x+y)/20),np.sin(y/5))**2>.9

# masked data represent noise, so lets put in some trash into the masked points
z[mask] = (np.random.random(size = (100,100))*10)[mask]

# masked data
z_masked = np.ma.masked_array(z, mask)

# "Conventional" filter
filter_kernelsize = 2

import scipy.ndimage
z_filtered_bad = scipy.ndimage.gaussian_filter(z_masked,filter_kernelsize)

# Lets filter it
import astropy.convolution.convolve
from astropy.convolution import Gaussian2DKernel
k = Gaussian2DKernel(1.5)

z_filtered = astropy.convolution.convolve(z_masked, k, boundary='extend')

### Plots:
fig, axes = plt.subplots(2,2)
plt.sca(axes[0,0])
plt.title('Raw Data')
plt.imshow(z)
plt.colorbar()

plt.sca(axes[0,1])
plt.title('Raw Data Masked')
plt.imshow(z_masked)
plt.colorbar()

plt.sca(axes[1,0])
plt.title('ndimage filter (ignores mask)')
plt.imshow(z_filtered_bad)
plt.colorbar()

plt.sca(axes[1,1])
plt.title('astropy filter (uses mask)')
plt.imshow(z_filtered)
plt.colorbar()

plt.tight_layout()