From your laptop to large-scale simulations with five lines of Python.
In the Generate a TurbSim Dataset tutorial, we used the 5MW_Baseline wind example,
which is based on the reference case described in "Definition of a 5-MW Reference Wind Turbine for Offshore
System Development".
In this tutorial, we’ll walk you through how to visualize the simulation output.

To follow this tutorial smoothly, please ensure you have the following tools and libraries installed.
Openfast_toolboxThis library is used to load TurbSim output files via the TurbSimFile class.
git clone http://github.com/OpenFAST/openfast_toolbox
cd openfast_toolbox
python -m pip install -e .
numpy and matplotlibThese libraries are essential for data processing and creating animations.
pip install numpy
pip install matplotlib
FFMPEG (optional)Required by matplotlib to generate .mp4 video files.
sudo apt install ffmpeg # on Linux
brew install ffmpeg # on Mac
We'll walk through a Python script that visualizes wind speed data from a .bts file generated by TurbSim. Step by step, we’ll explain each part of the code, and at the end you’ll find the complete script ready for you to run or customize.
Import necessary Python libraries:
numpy for numerical operationsmatplotlib for plotting and animationTurbSimFile from openfast_toolbox to load TurbSim output filesimport numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from openfast_toolbox.io import TurbSimFile
Load the .bts file using TurbSimFile. This file contains 3D wind field data over space and time.
ts = TurbSimFile("<your_bts_file>")
print(ts)
The 'u' component represents the longitudinal wind speed (x-direction).
We extract this and transpose it so we can animate it over time. The final array shape becomes time, z, y.
speeds = ts['u'] # Shape: [z, y, t]
print("speeds shape:", speeds.shape)
speed_x = np.transpose(speeds[0], axes=(0, 2, 1)) # [t, z, y]
print("speed_x shape:", speed_x.shape)
Determine the global minimum and maximum values for the color scale. This ensures the color map stays consistent across all frames in the animation.
vmin = np.min(speed_x)
vmax = np.max(speed_x)
Extract the height (z), width (y), and time (t) values for labeling and plotting.
z_vals = ts['z'] # Height levels
y_vals = ts['y'] # Horizontal (width)
t_vals = ts['t'] # Time
Configure the initial heatmap using imshow. The extent parameter ensures proper axis labeling, and origin='lower' makes the plot follow Cartesian coordinates. Label the axes and add a colorbar to indicate wind speed values.
fig, ax = plt.subplots()
extent = [y_vals[0], y_vals[-1], z_vals[0], z_vals[-1]]
heatmap = ax.imshow(speed_x[0],
cmap='viridis',
extent=extent,
origin='lower',
animated=True,
vmin=vmin,
vmax=vmax)
cbar = plt.colorbar(heatmap, ax=ax)
cbar.set_label("Wind Speed [m/s]")
ax.set_xlabel("Y [m]")
ax.set_ylabel("Z [m]")
ax.set_title("Ux [m/s]")
This function updates the heatmap for each time frame and displays the current time in the title.
def update(frame):
heatmap.set_array(speed_x[frame])
ax.set_title(f"t = {t_vals[frame]:.2f} s / Frame: {frame}")
return [heatmap]
Use FuncAnimation from matplotlib to create the animation. The animation is saved in both .gif and .mp4 formats for flexibility.
Note: Saving as
.mp4requires FFMPEG to be installed.
anim = FuncAnimation(fig,
update,
frames=speed_x.shape[0],
interval=50,
blit=True)
anim.save("heatmap_animation.gif", writer="pillow", fps=30)
anim.save("heatmap_animation.mp4", fps=30, dpi=150)
plt.close()
Below is the complete code needed to visualize the simulation output.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from openfast_toolbox.io import TurbSimFile
# Load .bts file
ts = TurbSimFile("<your_bts_file>")
print(ts)
# Extract longitudinal wind speed and reshape for animation
speeds = ts['u']
print("speeds shape:", speeds.shape)
speed_x = np.transpose(speeds[0], axes=(0, 2, 1))
print("speed_x shape:", speed_x.shape)
# Set up color limits
vmin = np.min(speed_x)
vmax = np.max(speed_x)
# Get coordinates
z_vals = ts['z']
y_vals = ts['y']
t_vals = ts['t']
# Set up figure and heatmap
fig, ax = plt.subplots()
extent = [y_vals[0], y_vals[-1], z_vals[0], z_vals[-1]]
heatmap = ax.imshow(speed_x[0],
cmap='viridis',
extent=extent,
origin='lower',
animated=True,
vmin=vmin,
vmax=vmax)
# Add colorbar and labels
cbar = plt.colorbar(heatmap, ax=ax)
cbar.set_label("Wind Speed [m/s]")
ax.set_xlabel("Y [m]")
ax.set_ylabel("Z [m]")
ax.set_title("Ux [m/s]")
# Update function for animation
def update(frame):
heatmap.set_array(speed_x[frame])
ax.set_title(f"t = {t_vals[frame]:.2f} s / Frame: {frame}")
return [heatmap]
# Create and save animation
anim = FuncAnimation(fig, update, frames=speed_x.shape[0], interval=50, blit=True)
anim.save("heatmap_animation.gif", writer="pillow", fps=30)
anim.save("heatmap_animation.mp4", fps=30, dpi=150)
plt.close()
Copy and customize it to create your own output animations.