I am trying to plot but it seems the square root can't work with negative number.
This is the problem I am trying to solve:
this is the errors:
RuntimeWarning: invalid value encountered in sqrt
x2 = ((16/1)*(y-5+2))**(1/2)
/home/browni/LasthrimProjection/Python/plot.py:58: RuntimeWarning: invalid value encountered in sqrt
Y3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.cos(V)
/home/browni/LasthrimProjection/Python/plot.py:59: RuntimeWarning: invalid value encountered in sqrt
Z3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.sin(V)
This is my MWE:
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line y = (3/16)x^2 + 3 and y = (1/16)x^2 + 5
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return (3/16)*(x**2) + 3 - 2
def r2(x):
return (1/16)*(x**2) + 5 - 2
def r3(x):
return ((16/3)*(x - 3 + 2)) ** (1/2)
def r4(x):
return ((16/1)*(x - 5 + 2)) ** (1/2)
def vx(x):
return np.pi*(r2(x)**2 - r1(x)**2)
def vy(x):
return np.pi*(r3(x)**2 - r4(x)**2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 4))
vy = sy.integrate(vy(x), (x, 0, 6))
n = 200
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
y = np.linspace(0, 6, n)
x1 = ((16/3)*y -3 + 2) ** (1/2)
x2 = ((16/1)*y - 5 + 2) ** (1/2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 4, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = ((3/16) * (U**2) + 3 - 2) * np.cos(V)
Z1 = ((3/16) * (U**2) + 3 - 2) * np.sin(V)
Y2 = ((1/16) * (U**2) + 5 - 2) * np.cos(V)
Z2 = ((1/16) * (U**2) + 5 - 2) * np.sin(V)
Y3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.cos(V)
Z3 = (((16/3) * (U - 3 + 2)) ** (1/2)) * np.sin(V)
Y4 = (((16/1)*(x - 5 + 2)) ** (1/2)) * np.cos(V)
Z4 = (((16/1)*(x - 5 + 2)) ** (1/2)) * np.sin(V)
ax1.plot(x1, y, label='$y = (3/16)x^2 + 3 - 2$')
ax1.plot(x2, y, label='$y = (1/16)x^2 + 5 - 2$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 6, n)
y1_inverse = np.power((16/3)*(x_inverse - 3 + 2), 1/2)
y2_inverse = np.power((16/1)*(x_inverse - 5 + 2), 1/2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $(3/16)x^2 + 3 - 2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y = (1/16)x^2 + 5 - 2$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
how to fix this?
Related
Question about using fill_between:
Using fill_between in the following snippet adds an unwanted vertical and horizontal line. Is it because of the parametric equation? How can I fix it?
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0, 2 * np.pi, 100)
x = 16 * np.sin(t)**3
y = 13 * np.cos(t) - 5 * np.cos(2*t) - 2*np.cos(3*t) - np.cos(4*t)
plt.plot(x,y, 'red', linewidth=2)
plt.fill_between(x, y, color = 'red', alpha = 0.2)
Here is the outcome:
You can use plt.fill to fill an area bounded by xy values. plt.fill_between fills between zero and a curve defined as y being a function of x.
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0, 2 * np.pi, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
plt.plot(x, y, 'deeppink', linewidth=2)
plt.fill(x, y, color='deeppink', alpha=0.2)
plt.axis('off')
plt.show()
Or in a loop:
t = np.linspace(0, 2 * np.pi, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
for r in np.linspace(1, 0.01, 50):
plt.fill(r * x, r * y, color=plt.cm.Reds(r))
plt.axis('off')
plt.show()
I have Python code to plot solid of revolution from function. How can I modify this to be able to create solid of revolution (revolved at certain x or y axis that we can choose. Precisely for these:
2n-regular polygons inscribed in a circle
Triangle, not only right angle, any kind of triangle
If it is a circle then it will become a torus
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line x - 2y = 0 and y^2 = 4x
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return x/2
def r2(x):
return 2*(x**(1/2))
def r3(x):
return 2*x
def r4(x):
return (x/2)**(2)
def vx(x):
return np.pi*(r2(x)**2 - r1(x)**2)
def vy(x):
return np.pi*(r3(x)**2 - r4(x)**2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 16))
vy = sy.integrate(vy(x), (x, 0, 8))
n = 200
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
y = np.linspace(0, 8, n)
x1 = (2*y)
x2 = (y / 2) ** (2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 16, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = (2 * U ** (1/2)) * np.cos(V)
Z1 = (2 * U ** (1/2)) * np.sin(V)
Y2 = (U / 2) * np.cos(V)
Z2 = (U / 2) * np.sin(V)
Y3 = ((U / 2) ** (2)) * np.cos(V)
Z3 = ((U / 2) ** (2)) * np.sin(V)
Y4 = (2*U) * np.cos(V)
Z4 = (2*U) * np.sin(V)
ax1.plot(x1, y, label='$y=x/2$')
ax1.plot(x2, y, label='$y=2 \sqrt{x}$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 8, n)
y1_inverse = np.power(2*x_inverse, 1)
y2_inverse = np.power(x_inverse / 2, 2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $y=x/2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y=2 \sqrt{x}$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
I have add the assumption of nonnegative for variables x and r so why I can't plot this?
this is my code:
# Calculate the surface area of y = sqrt(r^2 - x^2)
# revolved about the x-axis
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
x = sy.Symbol("x", nonnegative=True)
r = sy.Symbol("r", nonnegative=True)
def f(x):
return sy.sqrt(r**2 - x**2)
def fd(x):
return sy.simplify(sy.diff(f(x), x))
def f2(x):
return sy.sqrt((1 + (fd(x)**2)))
def vx(x):
return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
vxi = sy.Integral(vx(x), (x, -r, r))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()
n = 100
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
x = np.linspace(1, 3, 3)
# Plot the circle
y = np.sqrt(r ** 2 - x ** 2)
t = np.linspace(0, np.pi * 2, n)
xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])
ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")
# find the inverse of the function
y_inverse = x
x_inverse = np.sqrt(r ** 2 - y_inverse ** 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])
ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ \n Surface Area = {}".format(vxn))
plt.tight_layout()
plt.show()
That's because at this line of code:
y = np.sqrt(r ** 2 - x ** 2)
r is still a Sympy's symbol. You need to assign a number to r.
I have created this code by modification from previous topics.
I put the calculated volume on the volume plot. My questions are:
My plots are correct right?
My volume calculations are correct too right?
Why there will be negative volume? If I put the formula for vx(x) as r1 - r2 it will be negative. Should I put abs (absolute value) instead in the future? So I could careless If I put r1 - r2 or r2 - r1, the numbers is the same, only one has negative sign. What is the significant meaning of negative sign for volume? Do we need a careful thought when calculating volume through integration?
I do not use sympy is sympy better in calculating integral than numpy/scipy?
Thanks.. this is my code / MWE:
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line x - 2y = 0 and y^2 = 4x
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return x/2
def r2(x):
return 2*(x**(1/2))
def r3(x):
return 2*x
def r4(x):
return (x/2)**(2)
def vx(x):
return np.pi*(r2(x)**2 - r1(x)**2)
def vy(x):
return np.pi*(r3(x)**2 - r4(x)**2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 16))
vy = sy.integrate(vy(x), (x, 0, 8))
n = 200
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
y = np.linspace(0, 8, n)
x1 = (2*y)
x2 = (y / 2) ** (2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 16, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = (2 * U ** (1/2)) * np.cos(V)
Z1 = (2 * U ** (1/2)) * np.sin(V)
Y2 = (U / 2) * np.cos(V)
Z2 = (U / 2) * np.sin(V)
Y3 = ((U / 2) ** (2)) * np.cos(V)
Z3 = ((U / 2) ** (2)) * np.sin(V)
Y4 = (2*U) * np.cos(V)
Z4 = (2*U) * np.sin(V)
ax1.plot(x1, y, label='$y=x/2$')
ax1.plot(x2, y, label='$y=2 \sqrt{x}$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 8, n)
y1_inverse = np.power(2*x_inverse, 1)
y2_inverse = np.power(x_inverse / 2, 2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $y=x/2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y=2 \sqrt{x}$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
Your plots are correct except for the plot at the upper right. The boundary is a little bit off. I change the np.linspace for u to u = np.linspace(0, 8, n). However, the np.linspace of u for bottom right plot is correct, so it remains u = np.linspace(0, 16, n). You can create different variable names for them, but I just simply reassign u again to u itself, and create an X2. I attached the complete code below.
Your volume calculations are correct.
Upper right plot:
Bottom right plot:
It is impossible to have negative volume. You can solve the integrate by hand first and compare it to the numerical results. You can check:
https://math.stackexchange.com/questions/261244/is-there-a-fundamental-reason-that-int-ba-int-ab?rq=1
SymPy is for symbolic computation, but it can also do numerical integration, so does SciPy. My guess is that they both have dependencies on NumPy. I think you are fine as long as you implement them correctly.
# Compare the plot at xy axis with the solid of revolution toward x and y axis
# For region bounded by the line x - 2y = 0 and y^2 = 4x
# Plotting the revolution of the bounded region
# can be done by limiting the np.linspace of the y, u, and x_inverse values
# You can determine the limits by finding the intersection points of the two functions.
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
def r1(x):
return x / 2
def r2(x):
return 2 * (x ** (1 / 2))
def r3(x):
return 2 * x
def r4(x):
return (x / 2) ** (2)
def vx(x):
return np.pi * (r2(x) ** 2 - r1(x) ** 2)
def vy(x):
return np.pi * (r3(x) ** 2 - r4(x) ** 2)
x = sy.Symbol("x")
vx = sy.integrate(vx(x), (x, 0, 16))
vy = sy.integrate(vy(x), (x, 0, 8))
n = 200
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
y = np.linspace(0, 8, n)
x1 = (2 * y)
x2 = (y / 2) ** (2)
t = np.linspace(0, np.pi * 2, n)
u = np.linspace(0, 16, n)
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X = U
Y1 = (2 * U ** (1 / 2)) * np.cos(V)
Z1 = (2 * U ** (1 / 2)) * np.sin(V)
Y2 = (U / 2) * np.cos(V)
Z2 = (U / 2) * np.sin(V)
#######################################
u = np.linspace(0, 8, n) # linspace u for the upper right figure should be from 0 to 8 instead of 0 to 16
v = np.linspace(0, 2 * np.pi, n)
U, V = np.meshgrid(u, v)
X2 = U # created X2 here
Y3 = ((U / 2) ** (2)) * np.cos(V)
Z3 = ((U / 2) ** (2)) * np.sin(V)
Y4 = (2 * U) * np.cos(V)
Z4 = (2 * U) * np.sin(V)
ax1.plot(x1, y, label='$y=x/2$')
ax1.plot(x2, y, label='$y=2 \sqrt{x}$')
ax1.legend()
ax1.set_title('$f(x)$')
ax2.plot_surface(X2, Y3, Z3, alpha=0.3, color='red', rstride=6, cstride=12)
ax2.plot_surface(X2, Y4, Z4, alpha=0.3, color='blue', rstride=6, cstride=12)
ax2.set_title("$f(x)$: Revolution around $y$ \n Volume = {}".format(vy))
# find the inverse of the function
x_inverse = np.linspace(0, 8, n)
y1_inverse = np.power(2 * x_inverse, 1)
y2_inverse = np.power(x_inverse / 2, 2)
ax3.plot(x_inverse, y1_inverse, label='Inverse of $y=x/2$')
ax3.plot(x_inverse, y2_inverse, label='Inverse of $y=2 \sqrt{x}$')
ax3.set_title('Inverse of $f(x)$')
ax3.legend()
ax4.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax4.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
ax4.set_title("$f(x)$: Revolution around $x$ \n Volume = {}".format(vx))
plt.tight_layout()
plt.show()
I'm trying to plot a Chord diagram using Matplotlib. I am aware that already existing libraries, such as Plotly give me that functionality but I would really like to do it in matplotlib.
The code I have so far looks like this:
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig, ax = plt.subplots()
ax.axhline(0, color='black', linestyle='--')
ax.axvline(0, color='black', linestyle='--')
npoints = 3
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the arcs
numbers = [i for i in xrange(npoints)]
for i, j in itertools.product(numbers, repeat=2):
if i == j:
continue
x1y1 = x1, y1 = verts[i]
x2y2 = x2, y2 = verts[j]
# Calculate the centre of the Arc
mxmy = mx, my = [(x1 + x2) / 2, (y1 + y2) / 2]
r = np.sqrt((x1 - mx)**2 + (y1 - my)**2)
xy = [mx - r, my - r]
width = 2 * r
height = 2 * r
start_angle = np.arctan2(y1 - my, x1 - mx) * 180 / np.pi
end_angle = np.arctan2(y2 - my, x2 - mx) * 180 / np.pi
arc = patches.Arc(mxmy, width, height, start_angle, end_angle)
ax.add_patch(arc)
# Plot the points
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.annotate("1", (x[0], y[0]), xytext=(x[0] + .5, y[0] + .5))
ax.annotate("2", (x[1], y[1]), xytext=(x[1] - 1, y[1] + .5))
ax.annotate("3", (x[2], y[2]), xytext=(x[2] - 1, y[2] - 1))
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
Is anyone able to tell me why my plot looks like this?
I'm expecting something more like the following (image taken from Plotly)
Edit 1
I would like to draw arcs between the following points:
1 and 2
1 and 3
2 and 3
These arcs should ideally be on the inside.
Edit 2
After some further investigation I figured that the end_angle seems to be the root of the problem.
After #f5r5e5d pointing out the Bézier curve used in plotly, I've decided to give this one a go. It looks like this is the way to go in my case, too.
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
import sys
%matplotlib inline
fig, ax = plt.subplots()
npoints = 5
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the Bezier curves
numbers = [i for i in xrange(npoints)]
bezier_path = np.arange(0, 1.01, 0.01)
for a, b in itertools.product(numbers, repeat=2):
if a == b:
continue
x1y1 = x1, y1 = verts[a]
x2y2 = x2, y2 = verts[b]
xbyb = xb, yb = [0, 0]
# Compute and store the Bezier curve points
x = (1 - bezier_path)** 2 * x1 + 2 * (1 - bezier_path) * bezier_path * xb + bezier_path** 2 * x2
y = (1 - bezier_path)** 2 * y1 + 2 * (1 - bezier_path) * bezier_path * yb + bezier_path** 2 * y2
ax.plot(x, y, 'k-')
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
The code above plots what I wanted it do to. Some modifications on the style and it should be good to go.
Since the underlying problem was "how can I draw a chord diagram in matplotlib", I just want to let you know that there is now a python library to do that: mpl-chord-diagram.
You can just do pip install mpl-chord-diagram.
[disclaimer] I am the current maintainer [/disclaimer]