In essence, I need to make a square scatterplot from (0,1) to (0,1). The points within the quarter-circle centered at the origin need to be colored red, and the ones outside need to be colored blue. The way I was planning to do it was to make 2 scatterplots on the same graph, one with y1 = the range under the quarter-circle, and one with y2 = the range above the quarter-circle.
This is what I have so far:
import numpy as np
import matplotlib.pyplot as plt
x = np.random.random(500)
y1 < np.sqrt(1-x**2)
y2 > np.sqrt(1-x**2)
plt.xlim(0, 1)
plt.ylim(0, 1)
c1 = 'r'
c2 = 'b'
plt.scatter(x, y1, c=c1, cmap=plt.cm.jet)
plt.scatter(x, y2, c=c2, cmap=plt.cm.jet)
plt.axes().set_aspect(1)
plt.show()
This code gives me this plot, when I should be getting something like this. If someone could tell me how to fix my y1 and y2 values, I'd appreciate it. Thank you!
If you have a closer look at
y1 < np.sqrt(1-x**2)
y2 > np.sqrt(1-x**2)
... these two lines only give you boolean arrays. The code you posted actually gives you an error, which makes clear, you never saved y1 and y2.
So you rather should:
x = np.random.random(500)
y = np.sqrt(1-np.random.random(500)**2)
x1 = x[y<x]
y1 = y[y<x]
...
PS: adapted, now x and y are not directly correlated any more, corresponding to comments
IMO your approach doesn't quite get the point of the (assumed) topic. Afaics this is about calculating pi by the ratio of randomly distributed points in a (quarter) circle and its square.
The point is here to not calculate the points coordinates in any way, but to let them be distributed completely randomly. And afterwards, you can go and decide to plot this in whatever color you want with whatever underlying rule or algorithm.
Short, this would be my approach:
import numpy as np
import matplotlib.pyplot as plt
x = np.random.random(500)
y = np.random.random(500)
plt.xlim(0, 1)
plt.ylim(0, 1)
c = np.where(x**2 + y**2 < 1, 'r', 'b')
plt.scatter(x, y, c=c)
plt.gca().set_aspect(1)
plt.show()
for completeness an example of the assumed topic:
for i in range(1,9):
x = np.random.random(10**i)
y = np.random.random(10**i)
d = np.where(x**2 + y**2 < 1, 1, 0)
print(f'{10**i:>9} points: {4*np.sum(d)/d.size}')
# 10 points: 2.8
# 100 points: 3.08
# 1000 points: 3.076
# 10000 points: 3.1556
# 100000 points: 3.14456
# 1000000 points: 3.141884
# 10000000 points: 3.142634
# 100000000 points: 3.14158668
Related
I have two lines:
y=3x-4
y=-x+5
They intersect and form 4 regions in space (see image below).
Mathematically, the regions can be determined with the following inequations:
Region1: y<3x-4 & y>-x+5
Region2: y>3x-4 & y>-x+5
Region3: y>3x-4 & y<-x+5
Region4: y<3x-4 & y<-x+5
I want to fill all of those regions independently. However when I try to use plt.fill_between I can only get regions 1 and/or 3. How can I fill regions 2 and 4 using matplotlib and fill_between?
The code that I tried for region 3 is the following (source):
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,6,0.1)
y = np.arange(0,6,0.1)
# The lines to plot
y1 = 3*x - 4
y2 = -x+5
# The upper edge of polygon (min of lines y1 & y2)
y3 = np.minimum(y1, y2)
# Set y-limit, making neg y-values not show in plot
plt.ylim(0, 6)
plt.xlim(0, 6)
# Plotting of lines
plt.plot(x, y1,
x, y2)
# Filling between (region 3)
plt.fill_between(x, y2, y3, color='grey', alpha=0.5)
plt.show()
It's because you have set the limits incorrectly. Setting them as 2 horizontal lines, 6 and 0, does the trick. Note that I have changed the step of arange because, to have a neat picture, the intersection point (2.25 in your case) needs to belong to x range
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,6,0.05)
# The lines to plot
y1 = 3*x - 4
y2 = -x+5
# Set y-limit, making neg y-values not show in plot
plt.ylim(0, 6)
plt.xlim(0, 6)
# Filling between (region 3)
plt.fill_between(x, np.maximum(y1, y2), [6] * len(x), color='grey', alpha=0.5)
plt.fill_between(x, np.minimum(y1, y2), [0] * len(x), color='cyan', alpha=0.5)
plt.show()
The trick here is to define a new polygon based on the intersections of the lines, and use $y(x) = 0$ as your bottom border.
The implementation of this requires the following code. First we externally calculate and hardcode the intersection points between the lines and the a-axis:
# calculate intersections between lines and x axis
intersect_x = 9/4
y1_0 = 4/3
y2_0 = 5
Once we have those stored, we go through every x value. If the x value is greater than our starting point (where the climbing curve crosses the x-axis) but less than the intersection point, we add the climbing curve point at that x value. If the x-value is greater than the intersection point but less than the end point (where the falling curve crosses the x-axis), we add the falling curve point at that x value. At each step, we add a y=0 point to a new list to be our floor for the fill-in operation.
# here we manually perform the operation you were trying to do
# with np.minimum; we also add an (x, 0) point for
# every point we add to our new polygon
new_x = []
new_y = []
bottom_y = []
for x_dx, xx in enumerate(x):
if xx > y1_0 and xx < intersect_x:
new_x.append(xx)
new_y.append(y1[x_dx])
bottom_y.append(0)
elif xx < y2_0 and xx > intersect_x:
new_x.append(xx)
new_y.append(y2[x_dx])
bottom_y.append(0)
Now we just replace our fill_between code with the new curves:
plt.fill_between(new_x, new_y, bottom_y, color='grey', alpha=0.5)
This is the full code:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,6,0.1)
y = np.arange(0,6,0.1)
# The lines to plot
y1 = 3*x - 4
y2 = -x+5
# calculate intersections between lines and x axis
intersect_x = 9/4
y1_0 = 4/3
y2_0 = 5
# here we manually perform the operation you were trying to do
# with np.minimum; we also add an (x, 0) point for
# every point we add to our new polygon
new_x = []
new_y = []
bottom_y = []
for x_dx, xx in enumerate(x):
if xx > y1_0 and xx < intersect_x:
new_x.append(xx)
new_y.append(y1[x_dx])
bottom_y.append(0)
elif xx < y2_0 and xx > intersect_x:
new_x.append(xx)
new_y.append(y2[x_dx])
bottom_y.append(0)
# The upper edge of polygon (min of lines y1 & y2)
y3 = np.minimum(y1, y2)
# Set y-limit, making neg y-values not show in plot
plt.ylim(0, 6)
plt.xlim(0, 6)
# Plotting of lines
plt.plot(x, y1,
x, y2)
# Filling between (region 3)
plt.fill_between(new_x, new_y, bottom_y, color='grey', alpha=0.5)
plt.show()
And this is the result:
Happy coding!
This may sound like a very naive question. However, to me, it's quite fundamental: Can python plot variables without putting them into arrays or lists? I couldn't find much answer on the net or SO and please let me know if there's any duplicate.
I have the following code for demonstration:
import matplotlib.pyplot as plt
import numpy as np
x = 0.0
dx = 0.5
for i in range(10):
y = x**2
plt.plot(x,y)
x += dx
plt.show()
x = np.linspace(-0,.5,10)
y = x**2
plt.plot(x,y)
plt.show()
The first part doesn't plot (which is in an explicit for-loop) anything while the second part does (where both x and y are numpy arrays).
Is it possible to plot without storing variables in arrays or lists? plt.scatter(x,y,c='r') works but that doesn't produce any line plot.
Store the start and end of each segment to iteratively build a series of lines from datapoint to datapoint: (x0,y0) -> (x1, y1)
import matplotlib.pyplot as plt
import numpy as np
x0, y0 = 0, 0
x1 = 0.0
dx = 0.5
for i in range(10):
y1 = x1**2
plt.plot([x0,x1],[y0,y1], 'o-')
x0, y0 = x1, y1
x1 += dx
plt.show()
Note: this example will draw a line from (0,0) to (0,0) as the x1 value chosen is starting at 0.0
I would like to fill between 3 lines in matplotlib.pyplot but unfortunately the fill_between gives me opportunity to fill between only two lines. Any ideas how to deal with this?
Edit:
Ok, I did not explain what I really mean since I cannot add the picture with my current reputation so maybe in that way:
I try to fill the polygon bounded by these lines and I have no idea how because fill_between gives me opportunity to fill only area between two of them. Below the fill equation:
y <= 4- 2x
y <= 3 - 1/2x
y <= 1 - x
y >= 0
x >= 0
the x and y bigger than 0 is obvious. I start the plot from (0,0) but I still have 3 lines...
y <= 4- 2x
y <= 3 - 1/2x
y <= 1 - x
If you start the plot in point (0, 0), and therefore do not need to consider the area of the polygon not in the first quadrant, then this should do the trick in this particular situation:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,10,0.1)
# The lines to plot
y1 = 4 - 2*x
y2 = 3 - 0.5*x
y3 = 1 -x
# The upper edge of polygon (min of lines y1 & y2)
y4 = np.minimum(y1, y2)
# Set y-limit, making neg y-values not show in plot
plt.ylim(0, 5)
# Plotting of lines
plt.plot(x, y1,
x, y2,
x, y3)
# Filling between line y3 and line y4
plt.fill_between(x, y3, y4, color='grey', alpha='0.5')
plt.show()
To use fill_between, specify the X values first, than the two Y sets that you want to "fill between". An example is show below:
import pylab as plt
import numpy as np
X = np.linspace(0,3,200)
Y1 = X**2 + 3
Y2 = np.exp(X) + 2
Y3 = np.cos(X)
plt.plot(X,Y1,lw=4)
plt.plot(X,Y2,lw=4)
plt.plot(X,Y3,lw=4)
plt.fill_between(X, Y1,Y2,color='k',alpha=.5)
plt.fill_between(X, Y1,Y3,color='y',alpha=.5)
plt.show()
If, instead, you only wanted to fill between Y2 and Y3:
plt.fill_between(X, Y2,Y3,color='m',alpha=.5)
this would give you
Just compute the corner points of the polygon, i.e., the points where the lines intersect.
Then plot the polygon using pyplot.fill.
Example:
import matplotlib.pyplot as plt
# define corner points
x = [1,2,1,0]
y = [2,1,0,1]
# plot
plt.fill(x,y)
plt.show()
resulting Image:
The following formula is used to classify points from a 2-dimensional space:
f(x1,x2) = np.sign(x1^2+x2^2-.6)
All points are in space X = [-1,1] x [-1,1] with a uniform probability of picking each x.
Now I would like to visualize the circle that equals:
0 = x1^2+x2^2-.6
The values of x1 should be on the x-axis and values of x2 on the y-axis.
It must be possible but I have difficulty transforming the equation to a plot.
You can use a contour plot, as follows (based on the examples at http://matplotlib.org/examples/pylab_examples/contour_demo.html):
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1.0, 1.0, 100)
y = np.linspace(-1.0, 1.0, 100)
X, Y = np.meshgrid(x,y)
F = X**2 + Y**2 - 0.6
plt.contour(X,Y,F,[0])
plt.show()
This yields the following graph
Lastly, some general statements:
x^2 does not mean what you think it does in python, you have to use x**2.
x1 and x2 are terribly misleading (to me), especially if you state that x2 has to be on the y-axis.
(Thanks to Dux) You can add plt.gca().set_aspect('equal') to make the figure actually look circular, by making the axis equal.
The solution of #BasJansen certainly gets you there, it's either very inefficient (if you use many grid points) or inaccurate (if you use only few grid points).
You can easily draw the circle directly. Given 0 = x1**2 + x**2 - 0.6 it follows that x2 = sqrt(0.6 - x1**2) (as Dux stated).
But what you really want to do is to transform your cartesian coordinates to polar ones.
x1 = r*cos(theta)
x2 = r*sin(theta)
if you use these substitions in the circle equation you will see that r=sqrt(0.6).
So now you can use that for your plot:
import numpy as np
import matplotlib.pyplot as plt
# theta goes from 0 to 2pi
theta = np.linspace(0, 2*np.pi, 100)
# the radius of the circle
r = np.sqrt(0.6)
# compute x1 and x2
x1 = r*np.cos(theta)
x2 = r*np.sin(theta)
# create the figure
fig, ax = plt.subplots(1)
ax.plot(x1, x2)
ax.set_aspect(1)
plt.show()
Result:
How about drawing x-values and calculating the corresponding y-values?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 100, endpoint=True)
y = np.sqrt(-x**2. + 0.6)
plt.plot(x, y)
plt.plot(x, -y)
produces
This can obviously be made much nicer, but this is only for demonstration...
# x**2 + y**2 = r**2
r = 6
x = np.linspace(-r,r,1000)
y = np.sqrt(-x**2+r**2)
plt.plot(x, y,'b')
plt.plot(x,-y,'b')
plt.gca().set_aspect('equal')
plt.show()
produces:
Plotting a circle using complex numbers
The idea: multiplying a point by complex exponential () rotates the point on a circle
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
num_pts=20 # number of points on the circle
ps = np.arange(num_pts+1)
# j = np.sqrt(-1)
pts = np.exp(2j*np.pi/num_pts *(ps))
fig, ax = plt.subplots(1)
ax.plot(pts.real, pts.imag , '-o')
ax.set_aspect(1)
plt.show()
I would like to fill between 3 lines in matplotlib.pyplot but unfortunately the fill_between gives me opportunity to fill between only two lines. Any ideas how to deal with this?
Edit:
Ok, I did not explain what I really mean since I cannot add the picture with my current reputation so maybe in that way:
I try to fill the polygon bounded by these lines and I have no idea how because fill_between gives me opportunity to fill only area between two of them. Below the fill equation:
y <= 4- 2x
y <= 3 - 1/2x
y <= 1 - x
y >= 0
x >= 0
the x and y bigger than 0 is obvious. I start the plot from (0,0) but I still have 3 lines...
y <= 4- 2x
y <= 3 - 1/2x
y <= 1 - x
If you start the plot in point (0, 0), and therefore do not need to consider the area of the polygon not in the first quadrant, then this should do the trick in this particular situation:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,10,0.1)
# The lines to plot
y1 = 4 - 2*x
y2 = 3 - 0.5*x
y3 = 1 -x
# The upper edge of polygon (min of lines y1 & y2)
y4 = np.minimum(y1, y2)
# Set y-limit, making neg y-values not show in plot
plt.ylim(0, 5)
# Plotting of lines
plt.plot(x, y1,
x, y2,
x, y3)
# Filling between line y3 and line y4
plt.fill_between(x, y3, y4, color='grey', alpha='0.5')
plt.show()
To use fill_between, specify the X values first, than the two Y sets that you want to "fill between". An example is show below:
import pylab as plt
import numpy as np
X = np.linspace(0,3,200)
Y1 = X**2 + 3
Y2 = np.exp(X) + 2
Y3 = np.cos(X)
plt.plot(X,Y1,lw=4)
plt.plot(X,Y2,lw=4)
plt.plot(X,Y3,lw=4)
plt.fill_between(X, Y1,Y2,color='k',alpha=.5)
plt.fill_between(X, Y1,Y3,color='y',alpha=.5)
plt.show()
If, instead, you only wanted to fill between Y2 and Y3:
plt.fill_between(X, Y2,Y3,color='m',alpha=.5)
this would give you
Just compute the corner points of the polygon, i.e., the points where the lines intersect.
Then plot the polygon using pyplot.fill.
Example:
import matplotlib.pyplot as plt
# define corner points
x = [1,2,1,0]
y = [2,1,0,1]
# plot
plt.fill(x,y)
plt.show()
resulting Image: