I am trying to plot a 3D surface using SageMath Cloud but I am having some trouble because the documentation for matplotlib does not appear to be very thorough and is lacking in examples. Anyways the program I have written is to plot the Heat Equation solution that I got from analytical method.
The case is:
Heat Equation
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from sympy import *
from math import *
x = np.linspace(-8, 8, 100)
t = np.linspace(-8, 8, 100)
n = symbols('n', integer=True)
X, T = np.meshgrid(x, t)
an = float(2 / 10) * integrate(50 * sin(radians((2 * n + 1) * pi * x / 20)), (x, 0, 10))
Z = summation(an * e**(2 * n + 1 / 20)**2*pi**2*t * sin(radians((2 * n + 1) * pi * x / 20)), (n, 0, oo))
fig = plt.figure()
ax = fig.gca(projection = '3d')
surf = ax.plot_surface(X, T, Z,
rstride = 3,
cstride = 3,
cmap = cm.coolwarm,
linewidth = 0.5,
antialiased = True)
fig.colorbar(surf,
shrink=0.8,
aspect=16,
orientation = 'vertical')
ax.view_init(elev=60, azim=50)
ax.dist=8
plt.show()
I am getting this error when I run the code to plot the graph: "Error in lines 7-7
Traceback (most recent call last):
File "/projects/sage/sage-7.3/local/lib/python2.7/site-packages/smc_sagews/sage_server.py", line 968, in execute
exec compile(block+'\n', '', 'single') in namespace, locals
File "", line 1, in
File "/projects/sage/sage-7.3/local/lib/python2.7/site-packages/numpy/core/function_base.py", line 93, in linspace
dt = result_type(start, stop, float(num))
TypeError: data type not understood"
Please, any and all help is very greatly appreicated. I think the error comes up because I defined x = np.linspace(-8, 8, 100) and t = np.linspace(-8, 8, 100) but it is necessary to make the original program run. I am unsure of how to correct this so the graph plots properly. Thanks!
Your piece of code has problem with these two lines:
an = float(2 / 10) * integrate(50 * sin(radians((2 * n + 1) * pi * x / 20)), (x, 0, 10))
Z = summation(an * e**(2 * n + 1 / 20)**2*pi**2*t * sin(radians((2 * n + 1) * pi * x / 20)), (n, 0, oo))
I would suggest that you use simple for-loop to compute some other simple values for Z first to confirm that everythng is fine. Try replace the 2 lines with this:
# begin simple calculation for Z
# offered just for example
Z = []
y = symbols('y') # declare symbol for integration
for ix,ea in enumerate(x):
ans = integrate(y * sin(ea / 20), (y, 0, x[ix])) # integrate y from y=0 to y=x(ix)
Z.append(ans)
Z = np.array(Z, dtype=float) # convert Z to array
# end of simple calculation for Z
When you run it, you should get some plot as a result. For your intended values of Z, you have better situation to compute them with simple for-loop.
Related
I need to make a mask of hexagonal packed disks. The code below does the job, but I don't feel like its efficient. I'm learning python as well so I'd love to get some expert advice on how to do this more computationally efficient.
r = 0.01
X, Y = np.mgrid[0:1:1000j, 0:1:1000j]
mask = np.full(X.shape, False)
px, py = np.mgrid[r : 1 : 2 * r * np.sqrt(3), r : 1 + r + np.finfo(float).eps: 2 * r]
px = np.vstack((px, px + r * np.sqrt(3)))
py = np.vstack((py, py - r))
fig, ax = plt.subplots(figsize= (12, 12), dpi=50)
img = ax.imshow(mask * 1, cmap = 'gray', vmin = 0, vmax = 1, extent = [0, 1, 0, 1])
for i, _ in np.ndenumerate(px): #is this loop dumb and inefficient?
C = (X - px[i]) ** 2 + (Y - py[i]) ** 2
mask = mask | (C < r ** 2)
img.set_data(mask * 1)
ax.set_aspect(1)
In particular, is there a way to vectorize the for loop?
Thanks
It may be efficient to create a single tile of the pattern, and then repeat it horizontally and vertically as needed:
Create a tile:
import numpy as np
import matplotlib.pyplot as plt
r = 0.01
sq3 = np.sqrt(3)
samples = 1000
X, Y = np.mgrid[1:(1 + 2 * sq3):int(sq3 * samples) * 1j, 0:2:samples * 1j]
XY = np.c_[X.flatten(), Y.flatten()]
# coordinates of centers of disks; suffices to take disks of radius 1 here
p = np.array([[1, 1], [(1 + sq3), 0], [(1 + sq3), 2], [(1 + 2 * sq3), 1]])
# compute the distance from each point of XY to each disk center
dist = (XY**2).sum(axis=1).reshape(-1, 1) + (p**2).sum(axis=1) - 2 * (XY # p.T)
# mask points outside the disks
tile = (np.min(dist, axis=1) < 1).reshape(X.shape)
fig, ax = plt.subplots(figsize=(5, 5))
ax.set_aspect(1)
plt.imshow(tile, extent=[0, 2 * r, r, (1 + 2 * sq3) * r]);
It gives:
Repeat the tile:
# the number of times to repeat the tile in the horizontal and vertical directions
h, w = 20, 30
# donwsample the tile as needed and replicate
sample_rate = 10
mask = np.tile(tile[::sample_rate, ::sample_rate], (h, w))
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect(1)
ax.imshow(mask, extent=[0, 2 * r * w, 0, 2 * sq3 * r * h]);
This gives:
Hello I got this piece of code and I achieved to plot in the for-function n=1,5,10.
Now I should plot the zero as well. If I put for n_val in (0,1,5,10): ... , unfortunately I get the error x and y must have same first dimension, but have shapes (1000,) and (1,). Thank for helping me!
x = sp.symbols("x")
k = sp.symbols("k")
n = sp.symbols("n")
b = sp.Sum(((-1) ** k) * (x ** (2 * k + 1)) / sp.factorial(((2 * k + 1))), (k, 0, n))
c = sp.diff(b,x, 1)
a = sp.simplify(c)
for n_val in (1,5,10):
a_np = sp.lambdify(x, a.subs(n, n_val).doit())
x_vals = np.linspace(0, 10, 1000)
plt.plot(x_vals, a_np(x_vals), label=n_val)
plt.ylim(-2, 2)
plt.margins(x=0)
plt.legend(title='n', bbox_to_anchor=[1.02, 1.02], loc='upper left')
plt.tight_layout()
plt.show()
You could use the approach of Sympy: lambdify such that operations on arrays always result in arrays, also for constants?, which tests whether the function is constant and creates a constant numpy function in that case:
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
def np_lambdify(varname, func):
lamb = sp.lambdify(varname, func, modules=['numpy'])
if func.is_constant():
return lambda t: np.full_like(t, lamb(t))
else:
return lambda t: lamb(np.array(t))
x = sp.symbols("x")
k = sp.symbols("k")
n = sp.symbols("n")
b = sp.Sum(((-1) ** k) * (x ** (2 * k + 1)) / sp.factorial(((2 * k + 1))), (k, 0, n))
c = sp.diff(b, x, 1)
a = sp.simplify(c)
for n_val in (0, 1, 5, 10):
a_np = np_lambdify(x, a.subs(n, n_val).doit())
x_vals = np.linspace(0, 10, 1000)
plt.plot(x_vals, a_np(x_vals), label=n_val)
plt.ylim(-2, 2)
plt.margins(x=0)
plt.legend(title='n', bbox_to_anchor=[1.02, 1.02], loc='upper left')
plt.tight_layout()
plt.show()
I am trying to rewrite this article:We draw, programming. Machine-generated generation of artistic patterns in vector fields (Russian language) from pseudo-code in Python. I am new to ML, hence the following question arises: How to build a grid of angles and output it through PyCharm? I am at this stage:
import numpy as np
import math
import matplotlib.pyplot as plt
width = 100
height = 100
left_x = int(width * -0.5)
right_x = int(width * 1.5)
top_y = int(height * -0.5)
bottom_y = int(height * 1.5)
resolution = int(width * 0.01)
num_columns = int((right_x - left_x) / resolution)
num_rows = int((bottom_y - top_y) / resolution)
grid=np.ndarray((num_columns, num_rows))
grid[:,:]=math.pi * 0.25
In this code, I create a grid array in which 200 rows and 200 columns, into which the angle 'default_angle' is inserted. Please tell me whether I’m moving in the right direction and how to "draw" a grid, as in an attached link. So far I think I need to use matplotlib.
I believe you need to take a look at meshgrid from numpy
from the meshgrid documentation examples:
x = np.arange(-5, 5, 0.1)
y = np.arange(-5, 5, 0.1)
xx, yy = np.meshgrid(x, y, sparse=True)
z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
h = plt.contourf(x,y,z)
Edit. After seeing you r link a better resource is the matplotlib quiver demo
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(-10, 10, 1)
Y = np.arange(-10, 10, 1)
U, V = np.meshgrid(X, Y)
fig, ax = plt.subplots()
q = ax.quiver(X, Y, U, V)
ax.quiverkey(q, X=0.3, Y=1.1, U=10,
label='Quiver key, length = 10', labelpos='E')
plt.show()
You need to make several steps to recreate this:
create vector field based on some function or equation
normalize arrows for proper display
draw line
3.1. set starting parameters
3.2. set while out condition
3.3. calculate new position based on angle from starting point
3.4. get new position index --> net new angle
3.5. update starting positions
draw vector field and line
import numpy as np
import matplotlib.pyplot as plt
size = 50
X = np.arange(1, size, 1)
Y = np.arange(1, size, 1)
U, V = np.meshgrid(X, Y)
# Normalize the arrows:
U = U / np.sqrt(U**2 + V**2)
V = V / np.sqrt(U**2 + V**2)
# create angles field
data = []
for i in np.linspace(0, 180, Y.shape[0]):
data.append([i]*X.shape[0])
angle = np.array(data)
# set starting parameters
x_start_position = 2
y_start_position = 2
step_length = 1.0
point_angle = angle[x_start_position, y_start_position]
line_coordinates = [[x_start_position, y_start_position]]
# collect line points for each step
while x_start_position >= 2:
# calculate tep based on angle
x_step = step_length * np.cos(point_angle*np.pi/180)
y_step = step_length * np.sin(point_angle*np.pi/180)
# calculate new position
x_new_position = x_start_position + x_step
y_new_position = y_start_position + y_step
# get array index of new position
x_new_index = int(x_new_position)
y_new_index = int(y_new_position)
# get new angle
point_angle = angle[y_new_index, x_new_index]
# update start position
x_start_position = x_new_position
y_start_position = y_new_position
# collect results
line_coordinates.append([x_new_position, y_new_position])
# set line coordinates
line_data = np.array(line_coordinates)
x_line = line_data[:,0]
y_line = line_data[:,1]
# plot field
plt.quiver(X, Y, U, V, color='black', angles=angle, width=0.005)
# plot line
plt.plot(x_line, y_line, '-', color='red')
plt.show()
Output:
I am new to Python but I have prior experience in C++ and MATLAB.
I am currently writing a program to plot trajectories in phase space for nonlinear systems involving dy/dt and dx/dt. However, for more complicated functional forms, I received the Overflow Error. Is there any way for me to circumvent this problem? Thanks in advance!
These are my codes:
fig = plt.figure(figsize=(18,6))
dt = 0.01
def trajectories():
#initial conditions
x = y = 0.1
xresult = [x]
yresult = [y]
for t in xrange(10000):
# functional form: dx/dt = y, dy/dt = -r(x**2-1)*y-x
nextx = x + (r*x-y+x*y**2) * dt
nexty = y + (x + r*y + y**3) * dt
x, y = nextx, nexty
xresult.append(x)
yresult.append(y)
plt.plot(xresult, yresult)
plt.axis('image')
plt.axis([-3, 3, -3, 3])
plt.title('r = ' + str(r))
rs = [-1, -0.1, 0, .1, 1]
for i in range(len(rs)):
fig.add_subplot(1, len(rs), i + 1)
r = rs[i]
trajectories()
plt.show()
EDIT: this is the full traceback
Traceback (most recent call last):
File "/Users/Griffin/Atom/NumInt.py", line 33, in <module>
trajectories()
File "/Users/Griffin/Atom/NumInt.py", line 18, in trajectories
nextx = x + (r*x-y+x*y**2) * dt
OverflowError: (34, 'Result too large')
Your immediate error has to do with the fact that the Euler algorithm you are using for integration becomes unstable at the step size you are using. The ultimate problem is actually using the Euler algorithm. The code below uses scipy.integrate.odeint to handle the integration and does a better job due to being able to do variable step sizes. Some of the integration is still not perfect, but at least we get some results.
import numpy
import scipy.integrate
import matplotlib.pyplot as plt
def derivatives(states, t, r):
x, y = states
return [r*x - y + x*y**2,
x + r*y + y**3]
def trajectories(r):
initial_conditions = [0.1, 0.1]
times = numpy.linspace(0, 100, 1000)
result = scipy.integrate.odeint(derivatives, initial_conditions, times, args=(r,))
xresult, yresult = result.T
plt.plot(xresult, yresult)
plt.axis('image')
plt.axis([-3, 3, -3, 3])
plt.title('r = ' + str(r))
fig = plt.figure(figsize=(18,6))
rs = [-1, -0.1, 0, .1, 1]
for i, r in enumerate(rs, 1): # Avoid for i in range(len(rs))
fig.add_subplot(1, len(rs), i)
trajectories(r)
plt.show()
Result:
The equation I am working with is
$$
E = M_e + \sum_{n = 1}^N\frac{2}{n}\mathcal{J}_n(ne)\sin(nM_e)
$$
where $\mathcal{J}_n(x)$ is the nth Bessel function of the first kind.
As a test, I plotted the first 6 Bessel functions and everything worked out correctly. When I enter the argument of $n * e$, the plot isn't what I anticipated it to be.
import numpy as np
import pylab as py
import scipy.special as sp
x = np.linspace(0, 15, 500000)
for v in range(0, 6):
py.plot(x, sp.jv(v, x))
py.xlim((0, 15))
py.ylim((-0.5, 1.1))
py.legend(('$\mathcal{J}_0(x)$', '$\mathcal{J}_1(x)$', '$\mathcal{J}_2(x)$',
'$\mathcal{J}_3(x)$', '$\mathcal{J}_4(x)$', '$\mathcal{J}_5(x)$'),
loc = 0)
py.xlabel('$x$')
py.ylabel('$\mathcal{J}_n(x)$')
#py.title('Plots of the first six Bessel Functions')
py.grid(True)
#py.savefig('besseln0to6.eps', format = 'eps')
py.show()
e = 0.99
def E(M):
return (M + sum(2.0 / n * sp.jv(n * e, M) * np.sin(n * M)
for n in range(1, 3, 1)))
M = np.linspace(0, 2 * np.pi, 500000)
fig2 = py.figure()
ax2 = fig2.add_subplot(111, aspect = 'equal')
ax2.plot(E(M), M, 'b')
def E2(M):
return (M + sum(2.0 / n * sp.jv(n * e, M) * np.sin(n * M)
for n in range(1, 11, 1)))
ax2.plot(E2(M), M, 'r')
py.xlim((0, 2 * np.pi))
py.ylim((0, 2 * np.pi))
py.xlabel('Eccentric anomaly, $E$')
py.ylabel('Mean anomaly, $M_e$')
py.show()
The plot is supposed to look like for n = 10
The problem is the use of the Bessel function sp.jv(n * e, M) whereas it should be order, argument. That in turn leads to sp.jv(n , n * e) which generates the correct plot.