The anatomy of an ndarray in NumPy looks like this red cube below: (source: Physics Dept, Cornell Uni)

Once you leave the 2D space and enter 3D or higher dimensional spaces, the concept of rows and columns doesn't make much sense anymore. But still you can intuitively understand 3D arrays. For instance, considering your example:
In [41]: b
Out[41]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [42]: b.shape
Out[42]: (2, 2, 3)
Here the shape of b is (2, 2, 3). You can think about it like, we've two (2x3) matrices stacked to form a 3D array. To access the first matrix you index into the array b like b[0] and to access the second matrix, you index into the array b like b[1].
# gives you the 2D array (i.e. matrix) at position `0`
In [43]: b[0]
Out[43]:
array([[1, 2, 3],
[4, 5, 6]])
# gives you the 2D array (i.e. matrix) at position 1
In [44]: b[1]
Out[44]:
array([[ 7, 8, 9],
[10, 11, 12]])
However, if you enter 4D space or higher, it will be very hard to make any sense out of the arrays itself since we humans have hard time visualizing 4D and more dimensions. So, one would rather just consider the ndarray.shape attribute and work with it.
More information about how we build higher dimensional arrays using (nested) lists:
For 1D arrays, the array constructor needs a sequence (tuple, list, etc) but conventionally list is used.
In [51]: oneD = np.array([1, 2, 3,])
In [52]: oneD.shape
Out[52]: (3,)
For 2D arrays, it's list of lists but can also be tuple of lists or tuple of tuples etc:
In [53]: twoD = np.array([[1, 2, 3], [4, 5, 6]])
In [54]: twoD.shape
Out[54]: (2, 3)
For 3D arrays, it's list of lists of lists:
In [55]: threeD = np.array([[[1, 2, 3], [2, 3, 4]], [[5, 6, 7], [6, 7, 8]]])
In [56]: threeD.shape
Out[56]: (2, 2, 3)
P.S. Internally, the ndarray is stored in a memory block as shown in the below picture. (source: Enthought)

I have a 3d numpy array where the indices of each element represent the coordinates in the cartesian system and the value of each element represents something, let's say temperature. What would be the optimal way to visualize the temperature distribution in this space?
I have been looking at the 3d scatterplot approach in matplotlib, but I can't really make it work. Could someone point me in the right direction? Thanks!
python - Very Basic Numpy array dimension visualization - Stack Overflow
python - Visualizing a 3d numpy array of 1's and 0's - Stack Overflow
python - Creating a 3D plot from a 3D numpy array - Stack Overflow
Numpy 3D visualization
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()

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.
If you have a dset like that, and you want to just get the 1 values, you could use nonzero, which "returns a tuple of arrays, one for each dimension of a, containing the indices of the non-zero elements in that dimension.".
For example, we can make a simple 3d array:
>>> import numpy
>>> numpy.random.seed(29)
>>> d = numpy.random.randint(0, 2, size=(3,3,3))
>>> d
array([[[1, 1, 0],
[1, 0, 0],
[0, 1, 1]],
[[0, 1, 1],
[1, 0, 0],
[0, 1, 1]],
[[1, 1, 0],
[0, 1, 0],
[0, 0, 1]]])
and find where the nonzero elements are located:
>>> d.nonzero()
(array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2]), array([0, 0, 1, 2, 2, 0, 0, 1, 2, 2, 0, 0, 1, 2]), array([0, 1, 0, 1, 2, 1, 2, 0, 1, 2, 0, 1, 1, 2]))
>>> z,x,y = d.nonzero()
If we wanted a more complicated cut, we could have done something like (d > 3.4).nonzero() or something, as True has an integer value of 1 and counts as nonzero.
Finally, we plot:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, -z, zdir='z', c= 'red')
plt.savefig("demo.png")
giving

If you wanted to avoid using the nonzero option (for example, if you had a 3D numpy array whose values were supposed to be the color values of the data points), you could do what you do, but save some lines of code by using ndenumerate.
Your example might become:
for index, x in np.ndenumerate(dset):
if x == 1:
ax.scatter(*index, c = 'red')
I guess the point is just that you dont need to have nested for loops to iterate through multidimensional numpy arrays.
Try re-writing the update function as
def update(val):
frame = numpy.around(sframe.val)
l.set_data(data[frame,:,:])
so that you do not need to re-create all of the matplotlib objects every update
Seems like you need to cast frame number to int
def update(val):
frame = numpy.around(sframe.val)
l.set_data(data[int(frame),:,:])
otherwise it will throw an error:
l.set_data(data[frame,:,:])
IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices