Earlier last week I wrote about a hack to simulate bars with *matplotlib* in python. By coincidence, I later read up on the *mplot3d.axes3d* API, and found a **real** bar :)

.

.

.

The description is sparse:

[sourcecode language=”python”]bar3d(x, y, z, dx, dy, dz, color=’b’)

[/sourcecode]This enables us to create histograms of this type:

It has occasional problems with clipping: a plane in the back comes to the front erroneously. It also does not accept alpha, or other fancy features.

Note that the API is different from the regular bar. It takes in a numpy array for each of (lower left corner of bar), as well as :

For a histogram of the type shown above, *z* is zero (in the xy plane), and *dx*, *dy* are unity. *x*, *y* controls which grid the bar is plotted in, and *dz* the height of the bar. Together with the axes formatting, the code looks like the following. Included is a converter for changing a matrix input into the correct numpy arrays.

[sourcecode language=”python”]
import matplotlib.pyplot as plot

import mpl_toolkits.mplot3d

import numpy

import matplotlib.ticker as ticker

blankdata = [ [0,0,0,0,0,0],

[0,0,0,0,0,0],

[0,0,0,0,0,0],

[0,0,0,0,0,0],

[0,0,0,0,0,0],

[0,0,0,0,0,0],

[0,0,0,0,0,0],

[0,0,0,0,0,0] ]

def convert_grid_to_array(data):

""" This converts the explicit square grid into the x,y,dz positional arrays required for plot_matrix core """

xpos = [-100]
currentx = 0

ypos = [-100]
currenty = 0

dz = [0.05]
adata = numpy.array(data)

#print adata

#print adata.transpose()

arr_data_inverse = adata.transpose()

for i in arr_data_inverse:

for j in i:

zdata = arr_data_inverse[currentx][currenty]
if zdata != 0:

xpos.append(currentx)

ypos.append(currenty)

dz.append(zdata)

currenty=currenty+1

#print xpos, ypos, dz

currenty=0

currentx=currentx+1

return xpos, ypos, dz

def plot_matrix(data, color, filename):

fig = plot.figure()

ax2 = mpl_toolkits.mplot3d.Axes3D(fig)

xpos, ypos, dz = convert_grid_to_array(data)

zpos = numpy.zeros_like(xpos)

dx = 1 * numpy.ones_like(zpos)

dy = numpy.ones_like(zpos)

ax2.bar3d(xpos, ypos, zpos, dx, dy, dz, color=color)

ax2.set_xlim3d(0,6)

ax2.set_ylim3d(0,8)

ax2.set_zlim3d(0,15)

ax2.set_xlabel(‘$Duration / ms$’)

ax2.set_ylabel(‘$Conductance / pS$’)

ax2.set_zlabel(‘$Occurrences$’)

xformatter = (r’$10$’, r’$10^2$’, r’$10^3$’, r’$10^4$’, r’$10^5$’, r’$10^6$’)

ax2.w_xaxis.set_major_formatter(ticker.FixedFormatter(xformatter))

yformatter = ("", r’$3$’, r’$10$’, r’$30$’, r’$10^2$’, r’$3cdot10^2$’, r’$10^3$’, r’$3cdot10^3$’, r’$10^4$’)

ax2.w_yaxis.set_major_formatter(ticker.FixedFormatter(yformatter))

plot.savefig("".join([filename, ".pdf"]))

[/sourcecode]

There is a funny (xpos, ypos, dz) == (-100, -100, 0.05) line in the converter function. What this does is to validate empty input matrixes; the numpy functions *array.ones_like()* choke on empty arrays.

With this input, I think stacked 3D-histograms are also possible.