1

I made the following virtual "room" in a 3D array and would like to visualize it. I can't find a way to do so, please assist. The idea is to see a "3D image" of the array as a plot where the different values have different colours or just greyscale intensities, so that you can see the "patient" and the "detector" inside the "room":

import numpy as np


# Diff. values in the Room define objects: 0 = walls, 1 = inside room, 2 = patient's tissue, 3 = bone, 4 = x-ray detector

Room = np.array([[[0.0 for i in range(0,101,1)] for j in range(0,101,1)] for k in range(0,101,1)]) #The entire room with walls

for i in range(1,100,1):
    for j in range(1,100,1):
        for k in range(1,100,1):
            Room[i,j,k] +=1     # The room not counting the walls

for i in range(30,70,1):
    for j in range(30,70,1):
        for k in range(30,70,1):
            Room[i,j,k] +=1      #The patient's body (tissue)
            
for i in range(50,55,1):
    for j in range(50,55,1):
        for k in range(50,55,1):
            Room[i,j,k] +=1      #The patient's bone #1 
            
for i in range(58,63,1):
    for j in range(58,63,1):
        for k in range(58,63,1):
            Room[i,j,k] +=1      #The patient's bone #2

for i in range(88,92,1):
    for j in range(10,90,1):
        for k in range(10,90,1):
            Room[i,j,k] +=1      # X-ray Detector

2 Answers 2

2

You can create a 3 dimensional mesh grid with the help of matplotlib and numpy. Here is an example of such a plot. You just want to feed in your X,Y, and Z values as lists

import numpy as np
import matplotlib.pyplot as plt

# Create figure and add axis
fig = plt.figure(figsize=(8,6))
ax = plt.subplot(111, projection='3d')
    
# Remove gray panes and axis grid
ax.xaxis.pane.fill = False
ax.xaxis.pane.set_edgecolor('white')
ax.yaxis.pane.fill = False
ax.yaxis.pane.set_edgecolor('white')
ax.zaxis.pane.fill = False
ax.zaxis.pane.set_edgecolor('white')
ax.grid(False)
# Remove z-axis
ax.w_zaxis.line.set_lw(0.)
ax.set_zticks([])
    
# Create meshgrid
X, Y = np.meshgrid(np.linspace(0, 2, len(afm_data)), np.linspace(0, 2, len(afm_data)))
    
# Plot surface
plot = ax.plot_surface(X=X, Y=Y, Z=Z, cmap='YlGnBu_r', vmin=0, vmax=200)

There is also an article on this topic by Towards Data Science: https://towardsdatascience.com/visualizing-three-dimensional-data-heatmaps-contours-and-3d-plots-with-python-bd718d1b42b4

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot for your answer. Why did you "remove z-axis" and where is the Z value feed in your code? Sorry I don't see how the Z information is incorporated?
The Z axis tick marks were removed because they partially obstruct the view of the plot. You can leave the ticks there if you would like, or you could also remove the x and y ticks. It's simply preference!
Thank you, but how do you feed the 3D array "Room" that I made into that code to get a "3D" image/graph out? e.g. X, Y = np.meshgrid... I see but where is the Z component?
1

Just re-adding this because the first answer got deleted before I had the chance to respond:

Are you looking for a volume rendering approach? There's a broad range of Python libraries with that functionality available. This is an example link.

For your concrete case, you can use e.g. plotly and I just wrote a quick script for your data based on their tutorial:

import numpy as np
import plotly.graph_objects as go

# Generate nicely looking random 3D-field
np.random.seed(0)
l = 5
X, Y, Z = np.mgrid[:l, :l, :l]
vol = np.zeros((l, l, l))
#pts = (l * np.random.rand(3, 15)).astype(np.int)


# Diff. values in the Room define objects: 0 = walls, 1 = inside room, 2 = patient's tissue, 3 = bone, 4 = x-ray detector

Room = np.array([[[0.0 for i in range(0,102,1)] for j in range(0,102,1)] for k in range(0,102,1)]) #The entire room with walls

for i in range(1,100,1):
    for j in range(1,100,1):
        for k in range(1,100,1):
            Room[i,j,k] +=1     # The room not counting the walls

for i in range(30,70,1):
    for j in range(30,70,1):
        for k in range(30,70,1):
            Room[i,j,k] +=1      #The patient's body (tissue)
            
for i in range(50,55,1):
    for j in range(50,55,1):
        for k in range(50,55,1):
            Room[i,j,k] +=1      #The patient's bone #1 
            
for i in range(58,63,1):
    for j in range(58,63,1):
        for k in range(58,63,1):
            Room[i,j,k] +=1      #The patient's bone #2

for i in range(88,92,1):
    for j in range(10,90,1):
        for k in range(10,90,1):
            Room[i,j,k] +=1      # X-ray Detector

pts = Room.reshape(3,353736).astype(np.int)

print( tuple(indices for indices in pts) )

vol[tuple(indices for indices in pts)] = 1

from scipy import ndimage

vol = ndimage.gaussian_filter(vol, 0.5)
vol /= vol.max()

fig = go.Figure(data=go.Volume(
    x=X.flatten(), y=Y.flatten(), z=Z.flatten(),
    value=vol.flatten(),
    isomin=0.2,
    isomax=0.7,
    opacity=0.1,
    surface_count=25,
    ))
fig.update_layout(scene_xaxis_showticklabels=False,
                  scene_yaxis_showticklabels=False,
                  scene_zaxis_showticklabels=False)
fig.show()

The output is given below. Not sure if this is what you had in mind.

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.