Currently, I have some Python code to obtain equidistant points on the surface of a sphere. Now, I want to edit this code to obtain equidistant points on the surface of a hemisphere. I assume that there is some simple parameter I need to change, but I am still a Python novice.
My code:
from numpy import pi, cos, sin, arccos, arange
import mpl_toolkits.mplot3d
import matplotlib.pyplot as plt
num_pts = 10000
indices = arange(0, num_pts, dtype=float) + 0.5
phi = arccos(1 - 2*indices/num_pts)
theta = pi * (1 + 5**0.5) * indices
x, y, z = cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi);
fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 75
fig_size[1] = 75
plt.rcParams["figure.figsize"] = fig_size
plt.figure().add_subplot(111, projection='3d').scatter(x, y, z, s=1);
plt.show()
#saves the coordinates
import numpy as np
import sys
points = np.transpose(np.array([x,y,z]))
#np.savetxt(sys.stdout, points, fmt="%.6f")
np.savetxt('data.txt', points, fmt="%.6f")
Thank you for your help!
Simplest way from what you have:
X = np.stack((x,y,z)) # stack up all coordinates
mask = X[-1]>=0 # mask of elements where z coordinate larger than 0
x,y,z = X.T[mask].T # mask out the elements where z coordinate < 0
Then plot those points. you'll get a hemisphere I figure
Related
I am creating a circle and want to then develop a right-angle triangle, or any isometric form of a triangle. Whereby, I can take any line distance between two edges of the circle and draw arrows toward the peak point.
For example:
import numpy as np
import matplotlib.pyplot as plt
import math
theta = np.linspace(0, 2*np.pi, 100)
x1 = np.cos(theta)
y1 = np.sin(theta)
plt.plot(x1, y1)
for i in [min(y1), max(y1)]:
plt.plot(0, i, '-ok', mfc='C1', mec='C1')
plt.arrow(0,min(y1),0,2*max(y1),width=0.001,color='red',head_starts_at_zero=False)
plt.arrow(min(x1), (1/2)*min(y1), 2*max(x1), (1/2)*max(y1),width=0.001,color='red',head_starts_at_zero=False)
However, I cannot accurately get the distance between two points correct when i aim for any form of a triangle.
However, I can easily achieve it when setting y to 0 in the second arrow. Perhaps there is a general equation to do this?
Like this:
import numpy as np
import matplotlib.pyplot as plt
import math
theta = np.linspace(0, 2*np.pi, 100)
x1 = np.cos(theta)
y1 = np.sin(theta)
plt.plot(x1, y1)
x = np.array([0,120,240,0])
y = np.array([0,120,240,0])
x = np.cos( x * np.pi / 180 )
y = np.sin( y * np.pi / 180 )
plt.plot( x, y, color='red' )
plt.show()
Output:
In fact, if you choose ANY three angles, you'll get an inscribed triangle.
I want to scatter a lot of datapoints around a centre one (2.5,2.5) based on a given distance for each datapoint to the centre.
How do I do that and also evade duplicates/scatter them evenly around the centre?
Thanks in advance
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(6, 6))
N = 120
angles = np.linspace(0, 2 * np.pi, N)
c_x, c_y = (2.5, 2.5)
x_s, y_s = [], []
distances = list(np.arange(0, 5.5, 0.5))
for distance in distances:
for angle in angles:
x_s.append(c_x + distance * np.cos(angle))
y_s.append(c_y + distance * np.sin(angle))
plt.scatter(x_s, y_s, c="b", s=4)
plt.show()
To clarify, I wanted one point for each distance, and then the next one offset by 180 or 90 degrees. But I managed to complete it based on the code provided by Gustav Rasmussen:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(6, 6))
#default
N = 50
angles = np.linspace(0, 2 * np.pi, N)
c_x, c_y = (2.5, 2.5)
x_s, y_s = [], []
distances = list(np.arange(0, 5.5, 0.01))
i = angles.size/4
for distance in distances:
x_s.append(c_x + distance * np.cos(i))
y_s.append(c_y + distance * np.sin(i))
i += i
plt.scatter(x_s, y_s, c="b", s=4)
plt.show()
Here we can see 550 distances, displayed with the next one being displayed offset by approximately 90 degrees.
Last mention: When dealing with a dataset of bigger deviations it is better to do i = angles.size/2 as to keep the output somewhat circled
import cmath
import numpy as np
from matplotlib import pyplot as plt
from itertools import starmap
c = np.array(list(starmap(cmath.rect, [(v//40+1, v*np.pi/20) for v in range(120)])))
x = c.real+2.5
y = c.imag+2.5
plt.scatter(x, y)
Following the example in scikit-image doc I generate a spherical surface mesh with marching cubes algorithm. I want to center the unit sphere shell at the origin defined by the x,y,z grid. However, I cannot do that, since I don't know how to put x,y,z info with mpl_toolkits.mplot3d.art3d.Poly3DCollection. Here is the code:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from skimage import measure
import numpy as np
x, y, z = np.ogrid[-4:4:20j, -4:4:20j, -4:4:20j]
r = np.sqrt(x ** 2 + y ** 2 + z ** 2)
verts, faces, normals, values = measure.marching_cubes_lewiner(r,level=1)
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
mesh = Poly3DCollection(verts[faces])
mesh.set_edgecolor('k')
ax.add_collection3d(mesh)
plt.show()
The problem is that the marching_cubes_lewiner function does not take x,y,z into account. How can I center the resulting sphere at 0,0,0 as implied by the grid?
The measure.marching_cubes_lewiner takes the indices of the points in the grid for calculating the topology. It does not seem to have a way to specify the actual grid and neither any offset to it.
Hence you may manipulate the resulting verts in the desired way. I.e. one can first multiply by the difference between the grid points, effectively scaling the output, and then add the offset of the grid. In this case the transformation would be newverts = 0.42105 * oldverts - 4.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from skimage import measure
x, y, z = np.ogrid[-4:4:20j, -4:4:20j, -4:4:20j]
r = np.sqrt(x ** 2 + y ** 2 + z ** 2)
verts, faces, normals, values = measure.marching_cubes_lewiner(r, level=1)
verts *= np.array([np.diff(ar.flat)[0] for ar in [x,y,z]])
verts += np.array([x.min(),y.min(),z.min()])
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
mesh = Poly3DCollection(verts[faces])
mesh.set_edgecolor('k')
ax.add_collection3d(mesh)
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
ax.set_zlim(-2, 2)
plt.show()
so my question is how to make a polar plot r = f(theta) for a function f by calculating r for a range of values of theta and then converting r and theta to Cartesian coordinates using equations x = r cos(theta) , y = r sin(theta).
BUT I need to plot the spiral r = (theta)^2 for 0 <= theta <= 10*pi
this is what I have so far....not getting a spiral here.
#! /usr/bin/env python
import matplotlib.pyplot as plt
from math import cos, sin, pi
from numpy import linspace
for theta in linspace(0,10*pi):
r = ((theta)**2)
x = r*cos(theta)
y = r*sin(theta)
plt.plot(x,y)
plt.savefig("spiral.png")
plt.show()
You need to create a list of values, not just a single point. In your case, you keep calculating x and y, but never save them anywhere. So all you are plotting is the pair (x,y) after the last iteration.
x = []
y = []
for theta in linspace(0,10*pi):
r = ((theta)**2)
x.append(r*cos(theta))
y.append(r*sin(theta))
plt.plot(x,y)
plt.show()
Output
import numpy as np
import matplotlib.pyplot as plt
theta = np.radians(np.linspace(0,360*5,1000))
r = theta**2
x_2 = r*np.cos(theta)
y_2 = r*np.sin(theta)
plt.figure(figsize=[10,10])
plt.plot(x_2,y_2)
plt.show()
I am trying to use python3 and matplotlib (version 1.4.0) to plot a scalar function defined on the surface of a sphere. I would like to have faces distributed relatively evenly over the sphere, so I am not using a meshgrid. This has led me to use plot_trisurf to plot my function. I have tested it with a trivial scalar function, and am having the problem that there are rendering artefacts along the edges of the faces:
The code I used to create the plot is below:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.tri as mtri
from scipy.spatial import ConvexHull
def points_on_sphere(N):
""" Generate N evenly distributed points on the unit sphere centered at
the origin. Uses the 'Golden Spiral'.
Code by Chris Colbert from the numpy-discussion list.
"""
phi = (1 + np.sqrt(5)) / 2 # the golden ratio
long_incr = 2*np.pi / phi # how much to increment the longitude
dz = 2.0 / float(N) # a unit sphere has diameter 2
bands = np.arange(N) # each band will have one point placed on it
z = bands * dz - 1 + (dz/2) # the height z of each band/point
r = np.sqrt(1 - z*z) # project onto xy-plane
az = bands * long_incr # azimuthal angle of point modulo 2 pi
x = r * np.cos(az)
y = r * np.sin(az)
return x, y, z
def average_g(triples):
return np.mean([triple[2] for triple in triples])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y, Z = points_on_sphere(2**12)
Triples = np.array(list(zip(X, Y, Z)))
hull = ConvexHull(Triples)
triangles = hull.simplices
colors = np.array([average_g([Triples[idx] for idx in triangle]) for
triangle in triangles])
collec = ax.plot_trisurf(mtri.Triangulation(X, Y, triangles),
Z, shade=False, cmap=plt.get_cmap('Blues'), array=colors,
edgecolors='none')
collec.autoscale()
plt.show()
This problem appears to have been discussed in this question, but I can't seem to figure out how to set the edgecolors to match the facecolors. The two things I've tried are setting edgecolors='face' and calling collec.set_edgecolors() with a variety of arguments, but those throw AttributeError: 'Poly3DCollection' object has no attribute '_facecolors2d'.
How am I supposed to set the edgecolor equal to the facecolor in a trisurf plot?
You can set antialiased argument of plot_trisurf() to False. Here is the result: