2

I have scattered data and I am interpolating it to gridded data. Afterwards I draw everything with the contourf function. In the end I just want to draw everything inside a defined circle. Everything else should be white, but I don"t know how to achieve this. Is there a simple way to do this?

Here is my code:

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata


def func(x, y):
  return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2

grid_x, grid_y = np.mgrid[0:1:100j, 0:1:200j]

points = np.random.rand(1000, 2)
values = func(points[:,0], points[:,1])


grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')

plt.contourf(grid_x,grid_y,grid_z0)

plt.savefig("plot_data_in_circle.png")

Edit: I attach the plot which comes out from my code: picture produced by the current code

And this is how it should look like:

.

Jan SE
  • 337
  • 5
  • 13

1 Answers1

3

This can be done by creating a Circle patch, and then setting that as the clip_path.

To use a clip_path, one would usually store the artist on which you want to apply the clipping, and then use .set_clip_path on that. In this case, since you are using contourf, there is no method .set_clip_path, so we have to iterate over the PathCollections stored with the QuadContourSet returned from contourf, and set the clip path on each of them using the set_clip_path method.

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import matplotlib.patches as patches

def func(x, y):
  return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2

grid_x, grid_y = np.mgrid[0:1:100j, 0:1:200j]

points = np.random.rand(1000, 2)
values = func(points[:,0], points[:,1])


grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')

fig, ax = plt.subplots()
cs = ax.contourf(grid_x,grid_y,grid_z0)

circ = patches.Circle((0.6, 0.4), 0.3, transform=ax.transData)
for coll in cs.collections:
    coll.set_clip_path(circ)

plt.show()

enter image description here

tmdavison
  • 64,360
  • 12
  • 187
  • 165
  • Do you have any idea how to scale it to a circle? And I tried to include a colorbar. But this isn't working anymore – Jan SE Apr 30 '18 at 15:14
  • do you mean why is it an ellipse rather than a circle? That's because the aspect ratio of the axes is not equal. Try `ax.set_aspect('equal')` and you should see a circle. – tmdavison Apr 30 '18 at 15:23
  • Yes, thanks a lot!! This is a very nice answer ;) – Jan SE Apr 30 '18 at 15:37