python - Plotting a list of integer 3d values into Axes3d.voxels - Stack Overflow

admin2025-04-30  0

Let's start with where the list came from:

import tkinter as tk
from tkinter import ttk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,
NavigationToolbar2Tk)
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.figure import Figure as fg
import numpy as np

upar = (0, np.pi*2, 101)
vpar = (0, np.pi, 41)

# Map the parameters to an mgrid [[float, float]]
map = np.mgrid[upar[0]:upar[1]:upar[2] * 1j, 
   vpar [0]:vpar [1]:vpar [2] * 1j]
   .reshape(2, -1).T

#define a [u,v]->[x,y,z] parametric function 
def ball(ij):
    x0 = np.cos(ij[0]) * np.sin(ij[1])
    y0 = np.sin(ij[0]) * np.sin(ij[1])
    z0 = np.cos(ij[1])
    return [x0, y0, z0]

# Use function to create 3d map [[float, float, float]]
core = [ball(i) for i in map]

# Scale map for conversion to voxels
size = (15, 15, 9)
mantle = [np.multiply(i, size) for i in core]

# Create unique voxel point list [[int, int, int]]
crust = np.unique([[round(i) for i in j] for j in mantle])

# Split off top layer for light voxels and the rest dark
#  body cannot exist without layers to support it
roof = 8
cap = [lambda p : p[2] == roof - 1, crust]
body = if level>1 [lambda p : p[2] < roof - 1, crust] else None

# Set up the canvas and its figure
colors = ['#20e07f', '#000040']
fig = fg(figsize=(7, 7), dpi=100)
ax = fig.add_subplot(111, projection="3d")
ax.set_aspect('equal')
screen = FigureCanvasTkAgg(fig, master=self)
screen.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

# At last, the issue at hand
ax.voxels(cap, facecolors=colors[0], edgecolors=colors[1])
if (body!=None) ax.voxels(body, facecolors=colors[1], 
   edgecolors=colors[0])
screen.draw()

ValueError: Argument filled must be 3-dimensional

It's clear the voxels method cannot handle [[int, int, int]] as a data parameter. Is there either an alternative method that can, a way to convert the list to make it work, or even an inherited Axes3D that can actually plot this data?

The actual data points range from (-15,-15,0) to (15,15,9) so a traditional voxel array is not really feasible without some work.

Let's start with where the list came from:

import tkinter as tk
from tkinter import ttk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,
NavigationToolbar2Tk)
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.figure import Figure as fg
import numpy as np

upar = (0, np.pi*2, 101)
vpar = (0, np.pi, 41)

# Map the parameters to an mgrid [[float, float]]
map = np.mgrid[upar[0]:upar[1]:upar[2] * 1j, 
   vpar [0]:vpar [1]:vpar [2] * 1j]
   .reshape(2, -1).T

#define a [u,v]->[x,y,z] parametric function 
def ball(ij):
    x0 = np.cos(ij[0]) * np.sin(ij[1])
    y0 = np.sin(ij[0]) * np.sin(ij[1])
    z0 = np.cos(ij[1])
    return [x0, y0, z0]

# Use function to create 3d map [[float, float, float]]
core = [ball(i) for i in map]

# Scale map for conversion to voxels
size = (15, 15, 9)
mantle = [np.multiply(i, size) for i in core]

# Create unique voxel point list [[int, int, int]]
crust = np.unique([[round(i) for i in j] for j in mantle])

# Split off top layer for light voxels and the rest dark
#  body cannot exist without layers to support it
roof = 8
cap = [lambda p : p[2] == roof - 1, crust]
body = if level>1 [lambda p : p[2] < roof - 1, crust] else None

# Set up the canvas and its figure
colors = ['#20e07f', '#000040']
fig = fg(figsize=(7, 7), dpi=100)
ax = fig.add_subplot(111, projection="3d")
ax.set_aspect('equal')
screen = FigureCanvasTkAgg(fig, master=self)
screen.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

# At last, the issue at hand
ax.voxels(cap, facecolors=colors[0], edgecolors=colors[1])
if (body!=None) ax.voxels(body, facecolors=colors[1], 
   edgecolors=colors[0])
screen.draw()

ValueError: Argument filled must be 3-dimensional

It's clear the voxels method cannot handle [[int, int, int]] as a data parameter. Is there either an alternative method that can, a way to convert the list to make it work, or even an inherited Axes3D that can actually plot this data?

The actual data points range from (-15,-15,0) to (15,15,9) so a traditional voxel array is not really feasible without some work.

Share Improve this question asked Jan 4 at 22:58 David WallaceDavid Wallace 111 bronze badge 1
  • On what line is the error? what is your expected resulting plot? – rehaqds Commented Jan 5 at 7:39
Add a comment  | 

1 Answer 1

Reset to default 1

I interpreted part of the code and came up with this visualisation:

The issues were mainly with how you handle the coordinate data. I convert them to numpy arrays (shaped samples x 3) and supply them to the plotting function in the right format.

Modified example

%matplotlib widget
import numpy as np
import matplotlib.pyplot as plt

upar = (0, np.pi*2, 101)
vpar = (0, np.pi, 41)

# Map the parameters to an mgrid [[float, float]]
gmap = np.mgrid[
    upar[0]:upar[1]:upar[2] * 1j,
    vpar [0]:vpar [1]:vpar [2] * 1j
].reshape(2, -1).T

#define a [u,v]->[x,y,z] parametric function 
def ball(ij):
    x0 = np.cos(ij[0]) * np.sin(ij[1])
    y0 = np.sin(ij[0]) * np.sin(ij[1])
    z0 = np.cos(ij[1])
    return np.array([x0, y0, z0])

# Use function to create 3d map [[float, float, float]]
core = np.row_stack([ball(i) for i in gmap])
print(core.shape)

# Scale map for conversion to voxels
size = (15, 15, 9)
mantle = np.row_stack([np.multiply(i, size) for i in core])
print(mantle.shape)

# Create unique integer voxel points
crust = np.unique(mantle.round(), axis=0)
print(crust.shape)

# Split off top layer for light voxels and the rest dark
#  body cannot exist without layers to support it
roof = 8
is_cap = crust[:, 2] == (roof - 1)
print(is_cap.shape)
body = None#if level>1 [lambda p : p[2] < roof - 1, crust] else None

# Set up the canvas and its figure
colors = ['mediumspringgreen', 'black']
fig = plt.figure(figsize=(7, 7), dpi=100)
ax = fig.add_subplot(111, projection="3d")
ax.set_aspect('equal')

# ax.scatter(*crust.T, marker='s', s=10, facecolors=colors[0], edgecolors=colors[1])

#View roof slice only
ax.scatter(*crust[is_cap].T, marker='s', s=10, facecolors=colors[0], edgecolors=colors[1])
if (body!=None):
    ax.voxels(body, facecolors=colors[1], edgecolors=colors[0])

转载请注明原文地址:http://anycun.com/QandA/1746024726a91502.html