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.
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.
%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])