Alex Howard Alex Howard - 1 month ago 8
Python Question

How to plot 4D array with 2 sliders using PyPlot?

I have a 4D data set (for those who care, its an astronomical Position-Position-Temperature-Opacity image) in a numpy array, that I need to plot in an interactive way. While there are programs to do this, none of them can handle the unusual form that my data steps in (but I can worry about that, thats not part of the question).

I know how to get it plotting with one

Slider
, but really I need to plot the image with 2
Sliders
, one for each of temperature and opacity.

My MWE of a 3D array code is below:

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import numpy as np

array = np.random.rand(300,300,10)

axis = 2
s = [slice(0, 1) if i == axis else slice(None) for i in xrange(array.ndim)]
im = array[s].squeeze()

fig = plt.figure()
ax = plt.subplot(111)
l = ax.imshow(im, origin = 'lower')
axcolor = 'lightgoldenrodyellow'
ax = fig.add_axes([0.2, 0.95, 0.65, 0.03], axisbg=axcolor)

slider = Slider(ax, 'Temperature', 0, array.shape[axis] - 1,
valinit=0, valfmt='%i')

def update(val):
ind = int(slider.val)
s = [slice(ind, ind + 1) if i == axis else slice(None)
for i in xrange(array.ndim)]
im = array[s].squeeze()
l.set_data(im)
fig.canvas.draw()

slider.on_changed(update)

plt.show()


Any way to do it with 2 sliders?

EDIT: The problem I am having is I dont know how to expand to 2 sliders. Particularly how to adapt the line

s = [slice(0, 1) if i == axis else slice(None) for i in xrange(array.ndim)]


and how to modify the
update
function when I go from
np.random.rand(300,300,10)
to
np.random.rand(300,300,10,10)
. I supposed I will need to declare both a
T_axis = 2
and
B_axis = 3
rather than simply an
axis = 2
, but beyond that, I am rather stuck as to how to modify it.

Answer Source

As I interprete the data structure, you have an array of shape (300,300,n,m), where n is the number of temperatures and m is the number of opacities. The image to show for the ith temperature and the jth opacity is hence, array[:,:,i,j].

You now need of course two different silders where one determines the value of i and the other of j.

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import numpy as np

array = np.random.rand(300,300,10,9)
# assuming you have for each i=Temperature index and j =Opacity index
# an image array(:,:,i,j)

fig, ax = plt.subplots()
l = ax.imshow(array[:,:,0,0], origin = 'lower')

axT = fig.add_axes([0.2, 0.95, 0.65, 0.03])
axO = fig.add_axes([0.2, 0.90, 0.65, 0.03])

sliderT = Slider(axT, 'Temperature', 0, array.shape[2]-1, valinit=0, valfmt='%i')
sliderO = Slider(axO, 'Opacity', 0, array.shape[3]-1, valinit=0, valfmt='%i')

def update(val):
    i = int(sliderT.val)
    j = int(sliderO.val)
    im = array[:,:,i,j]
    l.set_data(im)
    fig.canvas.draw_idle()

sliderT.on_changed(update)
sliderO.on_changed(update)

plt.show()