Wednesday, April 8, 2026

Simultaneously build several python 3D plots via Multi-threaded Python 3.14t on Arch Linux

 For conversion three different plotting scripts building each one it's own surface into a multi-threaded (multi-process) version, we separate the code logic for each surface into a separate task. This allows CPU to calculate  simultaneously the paraboloid, sine wave, and Möbius strip.

To setup python3.14.3t on Arch Linux/CachyOS  along with aqtinstall via UV
   $ curl -LsSf https://astral.sh/uv/install.sh | sh
   $ uv python install 3.14t
   $ uv python list
   $ mkdir MULTITHREAD
   $ cd MULTITHREAD
   $ python3.14t -m venv .env
   $ source .env/bin/activate
   $ pip install aqtinstall
   $ pip install --upgrade pip
   $ pip install numpy matplotlib cxroots

❯ cat  plotMulti3Dpython12.py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.tri import Triangulation
from concurrent.futures import ProcessPoolExecutor

# --- Worker Functions for Parallel Execution ---

def calc_paraboloid():
    X = np.linspace(-5, 5, 100)
    Y = np.linspace(-5, 5, 100)
    X_grid, Y_grid = np.meshgrid(X, Y)
    Z = X_grid**2 + Y_grid**2
    return X_grid, Y_grid, Z

def calc_sine_tri():
    x = np.linspace(-5, 5, 50)
    y = np.linspace(-5, 5, 50)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(np.sqrt(X**2 + Y**2))
    triang = Triangulation(X.flatten(), Y.flatten())
    return triang, Z.flatten()

def calc_mobius():
    theta = np.linspace(0, 2*np.pi, 100)
    w = np.linspace(-0.5, 0.5, 10)
    theta_grid, w_grid = np.meshgrid(theta, w)
    r = 1 + w_grid * np.cos(theta_grid / 2)
    x = r * np.cos(theta_grid)
    y = r * np.sin(theta_grid)
    z = w_grid * np.sin(theta_grid / 2)
    return x, y, z

if __name__ == "__main__":
    # 1. Execute all three calculations in parallel
    with ProcessPoolExecutor() as executor:
        f1 = executor.submit(calc_paraboloid)
        f2 = executor.submit(calc_sine_tri)
        f3 = executor.submit(calc_mobius)

        # Gather results as they finish
        para_data = f1.result()
        sine_data = f2.result()
        mobi_data = f3.result()

    # 2. Plotting (Main Thread)

    # Plot 1: Paraboloid
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111, projection='3d')
    ax1.plot_surface(*para_data, cmap='inferno', edgecolor='none')
    ax1.set_title('Surface Plot of a Paraboloid')

    # Plot 2: Sine Triangulation
    fig2 = plt.figure()
    ax2 = fig2.add_subplot(111, projection='3d')
    ax2.plot_trisurf(sine_data[0], sine_data[1], cmap='viridis', edgecolor='none')
    ax2.set_title('Surface Triangulation Example')

    # Plot 3: Möbius Strip
    fig3 = plt.figure()
    ax3 = fig3.add_subplot(111, projection='3d')
    ax3.plot_surface(*mobi_data, cmap='coolwarm')
    ax3.set_title('Möbius Strip')

    plt.show()











You may also add to the bottom of ~/.bashrc                        function activatevenv() {
 # Names of possible virtualenv directories
 VIRTUALENV_DIRS=("venv/" "env/" ".env/" ".venv/" "${PWD##*/}")
 for dir in "${VIRTUALENV_DIRS[@]}"; do
   if [[ -d "${dir}" ]]; then
     # Found a possible venv directory
     # Try activating the venv
     if [[ -e "./${dir}/bin/activate" ]]; then
       source ./$dir/bin/activate
       echo "Virtual environment activated automatically"
       break
     fi
   fi
 done
}
# Extension for `cd` command in order to automatically activate virtual env when changing directories.
cd() {
 builtin cd $1
 # Try activating venv
 activatevenv
}


REFERENCES

https://medium.com/@ebimsv/mastering-matplotlib-part-6-exploring-3d-plotting-0423821e2e10