I am trying to create a meshgrid without some of the points that falls within the circle having specified coordinates and a radius. I am not able to subtract the grid points
One can not simply remove points from a meshgrid. Instead, you should create another array Z
as
Z = numpy.where((X-circle_x)**2+(Y-circle_y)**2>r**2,1,0)
and plot it as
plt.scatter(X,Y,Z)
You cannot remove the points within the arrays x
and y
. It is a 2D problem and the values that need to be removed from x
depend on y
and inversely.
What you can do is operate directly on the mesh you created (X
and Y
). For example,
import math
import numpy
import matplotlib.pyplot as plt
N = 200
x_start, x_end = -2.0, 2.0
y_start, y_end = -2.0, 2.0
x = numpy.linspace(x_start, x_end, N)
y = numpy.linspace(y_start, y_end, N)
circle_x, circle_y, r= 0.0, 0.0, 0.4
X, Y = numpy.meshgrid(x, y)
## Define points within circle
pts = (X-circle_x)**2+(Y-circle_y)**2 <= r**2
## Create a constant mask over grid
M = numpy.ones(X.shape)
## Assign 0 to mask for all points within circle
M[pts] = 0
size = 10
fig = plt.figure()
plt.imshow(M)
plt.show()
This does not remove any points from X
or Y
. If instead, you wish to only perform calculations on part of the points, you could do
pts = (X-circle_x)**2+(Y-circle_y)**2 > r**2
X = X[pts]
Y = Y[pts]
plt.scatter(X,Y)
plt.show()
If you'd like a scatter plot with just the points outside the circle, use boolean indexing to select only those points from your 2D "meshgridded" array:
import numpy as np
import matplotlib.pyplot as plt
N = 50
x_start, x_end = -2.0, 2.0
y_start, y_end = -1.0, 1.0
x = np.linspace(x_start, x_end, N)
y = np.linspace(y_start, y_end, N)
x0, y0, radius = 0.0, 0.0, 0.4
x, y = np.meshgrid(x, y)
r = np.sqrt((x - x0)**2 + (y - y0)**2)
outside = r > radius
fig, ax = plt.subplots()
ax.set(xlabel='X', ylabel='Y', aspect=1.0)
ax.scatter(x[outside], y[outside])
plt.show()
On the other hand, if you were using something like imshow
that requires 2D input, you'd need to either mask the values inside (as @JulienSpronck mentions, though it would be better to set them to np.nan
or use a masked array than to set them to 0) or set a clip path on the image.
For scatter, however, you don't need 2D input.
Boolean indexing on a nD array will return a 1d result. For example:
In [9]: x = np.arange(100).reshape(10, 10)
In [10]: x
Out[10]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
In [11]: x[x > 75]
Out[11]:
array([76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
93, 94, 95, 96, 97, 98, 99])
Because scatter
is only plotting points, it doesn't care how they're connected, and we can easily use the 1D result of boolean indexing.
On the other hand, if you wanted to plot an image, you'd need a 2D grid. In that case, you'd want to mask the values instead:
In [12]: np.ma.masked_where(x <= 75, x)
Out[12]:
masked_array(data =
[[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- -- -- -- --]
[-- -- -- -- -- -- 76 77 78 79]
[80 81 82 83 84 85 86 87 88 89]
[90 91 92 93 94 95 96 97 98 99]])
Notice how this maintains the 2D structure of the input.
On a side note, if this were a floating point array, you could just as easily set the values to np.nan
instead of masking them. When plotted with imshow
, the two will behave identically. I used a masked array in this case because x
was an integer array and can't contain NaN's.