How to plot blurred points in Matplotlib

2019-04-24 10:37发布

As the question says, I'm looking for a way to plot blurred points using Matplotlib. I don't want to plot a set of points and then apply a filter to blurry the whole image. Instead of it, I would like to plot a set of points, each of them with an associated level of blur.

Thank you in advance.

2条回答
Luminary・发光体
2楼-- · 2019-04-24 10:47

Here's another work around. You can display an image at each location instead of a marker using a BboxImage. That way you can blur or manipulate the image any way you want. This tutorial has more about BboxImages.

import matplotlib.pyplot as plt
from scipy import ndimage
from matplotlib.image import BboxImage
from matplotlib.transforms import Bbox, TransformedBbox
import numpy as np

# Create and save an image with just a marker in it
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.plot(0.5,0.5,'*',ms=200)
ax1.set_ylim(0,1)
ax1.set_xlim(0,1)
plt.axis('off')
fig1.savefig('marker.png')

# Read in the same marker image
marker = plt.imread('marker.png')

# New figure and data
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
x = 8*np.random.rand(10) + 1
y = 8*np.random.rand(10) + 1
sigma = np.arange(10,60,5)

# Blur the marker and image plot the blurred image at each data point. 
for xi, yi, sigmai in zip(x,y,sigma):
    markerBlur = ndimage.gaussian_filter(marker,sigmai) # Blur the marker image

    # Create an BboxImage for the blurred marker and add it to the plot. 
    bb = Bbox.from_bounds(xi,yi,1,1)  
    bb2 = TransformedBbox(bb,ax2.transData)
    bbox_image = BboxImage(bb2,
                           norm = None,
                           origin=None,
                           clip_on=False)

    bbox_image.set_data(markerBlur)
    ax2.add_artist(bbox_image)

ax2.set_xlim(0,10)
ax2.set_ylim(0,10)
plt.show()

blurred marker plot

查看更多
倾城 Initia
3楼-- · 2019-04-24 11:08

When you cannot make it, fake it.

import matplotlib.pyplot as plt
import numpy as np

# some random data
x = np.random.random(100)
y = np.random.random(100)
z = np.random.random(100)

# z reflects the amount of defocus at each dot
# if z=0, the point is small (1 pt)
# if z=1, the point is large (50 pt)
# each dot is composed of different layers
fig = plt.figure()
ax = fig.add_subplot(111)
for i in np.arange(.1,1.01,.1):
    ax.scatter(x, y, s=(50*i*(z*.9+.1))**2, color=(0,0,0,.5/i/10))

This gives:

enter image description here

This is by no means perfect, but something along these lines might suffice your needs. Things to consider:

  • the point size is now in absolute units, it does not scale (requires more maths for scaling)
  • if you want to have an equal amount of ink in each point, you will have to decrease the alpha value for larger blobs
  • do you want to have the blur diameter reflect the value (as here) or the blur area?
  • real "blur" is usually Gaussian, this is not; this can be made, but then the size and alpha scaling become a bit longer
  • what do you want to see happen when blurred points overlap each other?
  • when doing maths with alpha values and color values, remember the gamma function of the display

So, this is just an ugly fake. Sometimes they look good enough, sometimes not.

查看更多
登录 后发表回答