Visualization with ipywidgets

Let's visualize the evolution of the 2D temperature field as heat diffuses across the plate. We can do this interactively with the ipywidgets package.

Note: Depending on the current state of your Python installation, you may have to install the ipywidgets package, have notebook>=4.2.0, and enable widgets.

$ pip install ipywidgets
$ jupyter nbextension enable --py --sys-prefix widgetsnbextension

Start with the necessary imports.


In [ ]:
%matplotlib auto
import matplotlib.pyplot as plt
from ipywidgets import interact
from bmi_live.bmi_diffusion import BmiDiffusion

Define a function that runs the Diffusion model through its BMI for a fixed number of time steps. Store the temperture field from each time step in a list. Return the list.


In [ ]:
def run_model(n_steps=10):
    model = BmiDiffusion()
    model.initialize('../data/diffusion.yaml')
    grid_shape = model.get_grid_shape(0)
    
    initial_temp = model.get_value('plate_surface__temperature')
    initial_temp[20] = 100.
    model.set_value('plate_surface__temperature', initial_temp)
    
    temp = [initial_temp.reshape(grid_shape)]
    for _ in range(n_steps):
        model.update()
        new_temp = model.get_value('plate_surface__temperature')
        temp.append(new_temp.reshape(grid_shape))
    
    model.finalize()
    return temp

Run the model for awhile.


In [ ]:
temperature = run_model(50)

Define a function to visualize the temperature field at a time step (defined by an index into the list of temperature fields).


In [ ]:
xmin, xmax = 0., temperature[0].shape[1]
ymin, ymax = 0., temperature[0].shape[0]
im = plt.imshow(temperature[0], vmax=100, extent=[xmin, xmax, ymin, ymax], origin='upper', cmap='gist_stern')
plt.title('Plate Temperature')
plt.colorbar().ax.set_ylabel('Temperature (K)')

In [ ]:
def plot_temperature(time_index=0):
    im.set_data(temperature[time_index])

Make an interactive plot of temperature over time.


In [ ]:
interact(plot_temperature, time_index=(0, 50, 1))

Update the model interactively

Define a function to plot a 2D array of temperatures.


In [ ]:
def plot_temperature(temperature):
    plt.clf()
    xmin, xmax = 0., temperature.shape[1]
    ymin, ymax = 0., temperature.shape[0]
    plt.imshow(temperature, vmin=0., vmax=10., extent=[xmin, xmax, ymin, ymax], origin='upper', cmap='Reds')
    plt.title('Plate Temperature')
    # plt.colorbar().ax.set_ylabel('Temperature (K)')

We're going to use this a little later to interactively run and plot our model.

Create an object that runs the BmiHeat model until a given time and then plots the temperature field at that time. Notice that this would work with any BMI model - you would just have to change the name of the variable to plot. Since our model cannot run backward in time, we cache the temperature at each time step.


In [ ]:
class HeatRunner(object):
    def __init__(self, heat):
        self._heat = heat
        self._cache = []

    def run_and_plot(self, time_index):
        for _ in range(len(self._cache), time_index):
            self._heat.update()
            self._cache.append(
                heat.get_value('plate_surface__temperature').reshape(self._heat.get_grid_shape(0)))
        plot_temperature(self._cache[time_index - 1])

Instantiate the heat model and initialize it.


In [ ]:
heat = BmiDiffusion()
heat.initialize('../data/diffusion.yaml')

Set the initial temperature.


In [ ]:
init_temperature = heat.get_value('plate_surface__temperature')
init_temperature.shape = heat.get_grid_shape(0)
init_temperature[2, 2] = 100.
heat.set_value('plate_surface__temperature', init_temperature)

Run the model interactively over time. Note that as you move the slider, the model runs to the updated time.


In [ ]:
runner = HeatRunner(heat)
interact(runner.run_and_plot, time_index=(0, 100, 1))

In [ ]:
current_temperature = heat.get_value('plate_surface__temperature')
current_temperature.shape = heat.get_grid_shape(0)
current_temperature[5, 7] = 100.
heat.set_value('plate_surface__temperature', current_temperature)

In [ ]: