0

Alright so guys I have this 3d array of 1's and 0's which is supposed to represent a 3d object. 0 means that there is nothing there. 1 means that the objects exists in that co-ordinate. I need to display the 3d-object on my screen. It would be ideal for me to have a discrete 3 dimensoinal graph with value depending colors. I tried looking into glumpy and vispy but the documentation page seems to be down right now.

rjpj1998
  • 297
  • 1
  • 6
  • 23
  • A good answer will depend on the type of visualization you need (slices, volume, etc.). In any case for high level visualization you can consider: [VTK](http://www.vtk.org/download/), [Mayavi](http://docs.enthought.com/mayavi/mayavi/), [PyQtGraph](http://www.pyqtgraph.org/). [Vispy](http://vispy.org/) and [Glumpy](https://glumpy.github.io/) probably already have some kind of volume view so I would consider both a possibility. Other than those check if [Galry](https://github.com/rossant/galry/blob/master/docs/gallery.md) also has something like this. – armatita Jun 29 '17 at 12:47
  • Just an extra. [Blender](https://www.blender.org/) can also be used to do this. You can use Python, including numpy, inside blender itself. Check [this question](https://blender.stackexchange.com/questions/1187/is-there-a-tool-for-scientific-visualization-using-blender). – armatita Jun 29 '17 at 12:51
  • What do you mean by "value depending colors"? Surely whether or not the point appears in 3D is dependent on the value. Do you mean dependent on the index? – Tom Wyllie Jun 29 '17 at 13:34
  • See **[this answer](https://stackoverflow.com/questions/42611342/representing-voxels-with-matplotlib)** for the options you have using **matplotlib**. – ImportanceOfBeingErnest Mar 24 '18 at 11:25
  • The problem has been solved. – rjpj1998 Mar 25 '18 at 08:23

3 Answers3

4

I made a pull request to matplotlib that does exactly this, adding the ax3d.voxels function. Unfortunately, it hasn't been reviewed fully yet.

Update: This made it into matplotlib 2.1

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# your real data here - some 3d boolean array
x, y, z = np.indices((10, 10, 10))
voxels = (x == y) | (y == z)

ax.voxels(voxels)

plt.show()

resulting plot

Eric
  • 95,302
  • 53
  • 242
  • 374
  • Damn, gonna have to wait then? – rjpj1998 Jun 29 '17 at 16:30
  • You can always include the function there in your own code, using `voxels(ax3d, ...)` instead of `ax3d.voxels` – Eric Jun 29 '17 at 16:58
  • Man I am a complete noob with matplotlib. Could you redirect me to a detailed guide? – rjpj1998 Jul 01 '17 at 04:09
  • A detailed guide to using the function from that pull request? Just copy and paste the function from the diff – Eric Jul 01 '17 at 09:49
  • if i dont send an error I get: File "3d.py", line 30, in voxels color = next(self._get_patches_for_fill.prop_cycler)['color'] AttributeError: type object 'Axes3D' has no attribute '_get_patches_for_fill' And if i send colors, I get: self.xy_dataLim.update_from_data_xy(np.array([x, y]).T, not had_data) AttributeError: 'list' object has no attribute 'xy_dataLim' – rjpj1998 Jul 06 '17 at 12:24
  • How are you calling `voxels`? Sounds like you're not passing the first argument properly – Eric Jul 08 '17 at 20:58
  • https://pastebin.com/G9hHa0yq Here's my code. I should mention that i copied the voxel function from your pull request and rest of the code from your introduction to the pull request. I had to change the variable voxels to voxelz because python was trying to call the variable instead of the function. – rjpj1998 Jul 09 '17 at 16:16
  • I don't know why you wrote `voxels(Axes3D,voxelz)` - it should be `voxels(ax, voxelz)`. In python, `some_obj.method(...)` is the same as `SomeClass.method(some_obj, ...)` where `SomeClass == type(some_obj)` (provided there is no `@classmethod` or `@staticmethod` decorator) – Eric Jul 10 '17 at 10:36
  • Another option is to simply add `Axes3D.voxels = voxels`, and then the method form will work – Eric Jul 10 '17 at 10:37
1

Use np.where to extract the coordinates, and matplotlib for the 3D plot.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

data = np.zeros(shape=(20, 20, 20), dtype=np.bool_)
np.fill_diagonal(data, True)

fig = plt.figure()
Axes3D(fig).plot_wireframe(*np.nonzero(data))
plt.show()

This plots a basic 3D wireframe according to where the ones appeared in the matrix. You may wish to use plot_surface or scatter in place of plot_wireframe. See the documentation for more information.

Eric
  • 95,302
  • 53
  • 242
  • 374
Tom Wyllie
  • 2,020
  • 13
  • 16
  • I dont have to use numpy.where because my array already only has 1's and 0's. while it looks like its working for the most part, can you recommend me something more faster, this is way too laggy. – rjpj1998 Jun 29 '17 at 15:58
  • Is `np.where` taking a long time? I would be very surprised if that was the case. Matplotlib, however, is a pile of garbage so I would not be surprised if the rendering of the 3D plot is very slow. You may wish to look into renderring it without popping up the windows and just saving the images as files, but other than that I'm afraid I have no better suggestions. – Tom Wyllie Jun 29 '17 at 16:00
  • This doesn't do the right thing, does it? Doesn't it just plot a line through every point in the mesh in scanline order? Try it with `data[8:12,8:12,8:12] = 1` after the current initialization – Eric Jun 29 '17 at 17:14
  • Also, I've edited your answer to use boolean arrays - feel free to revert, but it seemed easier than explaining in the comments – Eric Jun 29 '17 at 17:15
  • You're right @Eric, `wireframe` doesn't do the right thing. OP's exact use case is not clear and I felt this was the most likely to be suitable, but of course isn't a perfect solution hence why I listed `scatter` and `plot_surface` as possible alternatives. Seems like the solution from your PR is the best one though. I'll edit this answer once that's merged. – Tom Wyllie Jun 29 '17 at 22:38
0

Could you save the x,y,z coordinates of each '1' point to a file and display it with cloudcompare or meshlab?

Cloudcompare will even let you store other values after each point and choose how to map these onto colour

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263