Python mayavi : How to draw spheres at random positions in 3D space

1.2k Views Asked by At

This is a code for generating random sized spheres with mayavi,

I want to make the spheres to be connected with each other by the surface or with a bond line:

  1. Spheres must be at random positions in 3D space
  2. Spheres must be with the same radius
from mayavi import mlab
import numpy as np

[phi,theta] = np.mgrid[0:2*np.pi:12j,0:np.pi:12j]
x = np.cos(phi)*np.sin(theta)
y = np.sin(phi)*np.sin(theta)
z = np.cos(theta)

def plot_sphere(p):
    
    r,a,b,c = p
    r=1
    return mlab.mesh(r*x+a, r*y+b, r*z )  


for k in range(8):
    c = np.random.rand(4)
    c[0] /= 10.
    plot_sphere(c)

mlab.show()
2

There are 2 best solutions below

12
On

From sphere equation:

enter image description here

So when passing arguments to mlab.mesh we would like to set [x_0, y_0, z_0] for each sphere such as they are at different positions from the axis.

The problem was that the numbers generated by np.random.rand(4) are random, but not distinct.

Let's modify so that the arguments [x_0, y_0, z_0] are random and distinct:

  1. We use sample to get distinct index numbers in a cube
  2. We convert using index_to_3d the index to an (x, y, z) coordinates

The radius, r, can be adjusted to have more or less spacing between the spheres.

Spheres at 3D space

Code:

import random
from itertools import product

from mayavi import mlab
import numpy as np

[phi, theta] = np.mgrid[0:2 * np.pi:12j, 0:np.pi:12j]
x = np.cos(phi) * np.sin(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(theta)


def plot_sphere(x_0, y_0, z_0):
    r = 0.5
    return mlab.mesh(r * x + x_0, r * y + y_0, r * z + z_0)

SPHERES_NUMBER = 200

CUBE_SIZE = 10

def index_to_3d(i, SIZE):
    z = i // (SIZE * SIZE)
    i -= (z * SIZE * SIZE)
    y = i // SIZE
    x = i % SIZE
    return x, y, z

random_tuples = [index_to_3d(i, CUBE_SIZE) for i in random.sample(range(CUBE_SIZE ** 3), SPHERES_NUMBER)]

for k in range(SPHERES_NUMBER):
    x_0, y_0, z_0 = random_tuples[k]
    plot_sphere(x_0, y_0, z_0)

mlab.show()

Output:

enter image description here

Spheres cluster

Let's utilize gauss to create coordinates for the cluster points.

Code:

import random
from itertools import product

from mayavi import mlab
import numpy as np

[phi, theta] = np.mgrid[0:2 * np.pi:12j, 0:np.pi:12j]
x = np.cos(phi) * np.sin(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(theta)


def plot_sphere(x_0, y_0, z_0):
    r = 0.5
    return mlab.mesh(r * x + x_0, r * y + y_0, r * z + z_0)

SPHERES_NUMBER = 200

def create_cluster(CLUSTER_SIZE):
    means_and_deviations = [(1, 1.5), (1, 1.5), (1, 1.5)]
    def generate_point(means_and_deviations):
        return tuple(random.gauss(mean, deviation) for mean, deviation in means_and_deviations)
    cluster_points = set()
    while len(cluster_points) < CLUSTER_SIZE:
        cluster_points.add(generate_point(means_and_deviations))
    return list(cluster_points)

cluster_points = create_cluster(SPHERES_NUMBER)

for k in range(SPHERES_NUMBER):
    x_0, y_0, z_0 = cluster_points[k]
    plot_sphere(x_0, y_0, z_0)

mlab.show()

Output:

enter image description here

0
On

What about just using the mayavi points3d function? By default the mode parameter is set to sphere and you can set the diameter by using the scale_factor parameter. You can also increase the resolution of the sphere by varying the resolution parameter.

Here is the code:

def draw_sphere(
        center_coordinates,
        radius,
        figure_title,
        color,
        background,
        foreground
):
    sphere = mlab.figure(figure_title)
    sphere.scene.background = background
    sphere.scene.foreground = foreground

    mlab.points3d(
        center_coordinates[0],
        center_coordinates[1],
        center_coordinates[2],
        color=color,
        resolution=256,
        scale_factor=2*radius,
        figure=sphere
    )

Regarding the connected with each other by the surface issue, your explanation is poor. Maybe you mean just tangent spheres, but I would need more details.