Lin
Lin

Reputation: 1203

Expanding "pixels" on matplotlib + numpy array

I have created a random data source that looks like this:

Regular random source data

This is the code I use to gennerate and plot the first image.

import pandas as pd
import numpy as np
import numpy.ma as ma
import matplotlib.pyplot as plt

msize=25
rrange=5
jump=3
start=1
dpi=96
h=500
w=500

X,Y=np.meshgrid(range(0,msize),range(0,msize))
dat=np.random.rand(msize,msize)*rrange

msk=np.zeros_like(dat)
msk[start::jump,start::jump].fill(1)
mdat=msk*dat
mdat[mdat==0]=np.nan
mmdat = ma.masked_where(np.isnan(mdat),mdat)

fig = plt.figure(figsize=(w/dpi,h/dpi),dpi=dpi)

cmap = plt.get_cmap('RdYlBu')
cmap.set_bad(color='#cccccc', alpha=1.)

plot = plt.pcolormesh(X,Y,mmdat,cmap=cmap)

plot.axes.set_ylim(0,msize-1)
plot.axes.set_xlim(0,msize-1)


fig.savefig("masked.png",dpi=dpi)

Often this data source isn't so evenly distributed (but this is another subject).

Is there any kind of interpolation that makes the points "spill out" from its position?

Something like we take that light yellow point @(1,1) and turn all region around it (1 radius in taxi driver metric + diagonals) with the same color/value (for every valid point on image, nans will not be expanded)?

As I "gimped" on this image, on the three most lower/left values, the idea is find a way to do the same in all valid points, and not use gimp for that ;-):

Fake mask

After some thinking I arrived on this solution

import numpy as np
import matplotlib.pyplot as plt

t=np.array([
[ 0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0 ],
[ 0,0,2,0,0,4,0,0 ],
[ 0,0,0,0,0,0,0,0 ], 
[ 0,0,0,0,0,0,0,0 ],
[ 0,0,3,0,0,1,0,0 ],
[ 0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0 ]])


def spill(arr, nval=0, m=1):
    narr=np.copy(arr)
    for i in range(arr.shape[0]):
        for j in range(arr.shape[1]):
            if arr[i][j] != nval:
                narr[i-m:i+m+1:1,j-m:j+m+1:1]=arr[i][j]                    
    return narr

l=spill(t)
plt.figure()
plt.pcolormesh(t)
plt.savefig("notspilled.png")
plt.figure()
plt.pcolormesh(l)
plt.savefig("spilled.png")
plt.show()

This solution didn't make me very happy because the double for loop inside the spill() function :-/

Here are the output from the last code

This one isn't spilled Not spilled

This one was sppilled:

spilled

How can I enhance the code above to eliminate the double loop.

Upvotes: 1

Views: 189

Answers (1)

jakevdp
jakevdp

Reputation: 86328

You could do this with a 2D convolution. For example:

from scipy.signal import convolve2d

def spill2(arr, nval=0, m=1):
    return convolve2d(arr, np.ones((2*m+1, 2*m+1)), mode='same')

np.allclose(spill(t), spill2(t))
# True

Be aware that as written, the results will not match if nval != 0 or if the spilled pixels overlap, but you can probably modify this to suit your needs.

Upvotes: 1

Related Questions