Latest release 1.0.11 now available on PyPi and Conda-forge

[[ visible ? '▲ HIDE' : '▼ SHOW BANNER' ]]

|||

tfv 1.0.11 documentation

Quick search

  • API Reference
  • Examples Gallery
    • Tutorial 1. TUFLOW FV Post-Processing Using Xarray
    • Tutorial 2. Introductory Matplotlib Plot Composition
    • Tutorial 3: Working With Gridded Boundary Condition Data
    • Tutorial 4. Introduction to the Particle Tracking Module Tools
    • Gallery 1: Timeseries Plots
    • Gallery 2: Profile Plots
    • Gallery 3: Sheet Plots
    • Gallery 4: Curtain Plots
    • Gallery 5: Combined Plots
    • Gallery 6: Particle Tracking Plots
    • Gallery 7: Miscellaneous

Gallery 6: Particle Tracking Plots¶

Plot particle tracking outputs from TUFLOW FV’s Particle Tracking Module.

This notebook is used in combination with the TUFLOW FV Python Toolbox (tfv) package.

These Python tools have been recently updated (May 2025) to use a familiar workflow to the hydrodynamic post processing tools with the .tfv accessor.

IMPORTANT: This module is under active development and has been released on the basis of obtaining early feedback. Please contact TUFLOW Support with issues / requests / feedback when using this new module.

from pathlib import Path

import matplotlib.pyplot as plt
import tfv.xarray
import xarray as xr

Load Results¶

We’re using two sets of results to show off different functionality.

folder = Path('../../data')

# Load up our first PTM and TFV Domain Result
ptm1 = xr.open_dataset(folder / 'PTM_002_ptm.nc', decode_timedelta=True).tfv
fv1 = xr.open_dataset(folder / 'PTM_002.nc').tfv

# Load up our second PTM and TFV Domain Result
ptm2 = xr.open_dataset(folder / 'PTM_005_ptm.nc', decode_timedelta=True).tfv
fv2 = xr.open_dataset(folder / 'PTM_005.nc').tfv

Scatter Plots¶

Plot Basic¶

The general purpose function that we use for filtering particles is .get_particles. That function is ran whenever you use a plotting function so you can just put in your filters here for ease of use.

# Pick a time to plot - we'll sue the same throughout the tutorial. 
# You can enter a datetime e.g "2011-05-01 02:00"; 
# or just simple integer indexing, e.g., "-1" gives you the final timestep

time = -1 
fig, ax = plt.subplots()
ax.set_aspect('equal')

# Draw the mesh in the background
fv1.plot_mesh(ax=ax)

ptm1.plot(time=time, datum='height', limits=(0, 1), ax=ax, s=5, c='k', label='Bed (0m - 1m)')
ptm1.plot(time=time, datum='depth', limits=(0, 1), ax=ax, s=5, c='pink', label='Surface (0m - 1m)')

ax.legend()

plt.show()
../../../_images/6d01fe1fe4253f8229bda5e6f51ac7e9f27a3d1b09345371d7dadc0b237ebc67.png

Plot Groups¶

fig, ax = plt.subplots()
ax.set_aspect('equal')

# Draw the mesh in the background
fv2.plot_mesh(ax=ax)

ptm2.plot(time=time, ax=ax, s=5, c='green', group_ids=1, label='Clay')
ptm2.plot(time=time, ax=ax, s=5, c='black', group_ids=2, label='Silt')
ptm2.plot(time=time, ax=ax, s=5, c='yellow', group_ids=3, label='Fine Sand')
ptm2.plot(time=time, ax=ax, s=5, c='brown', group_ids=4, label='Coarse Sand')

ax.legend()

plt.show()
../../../_images/51024359d38070e4d73a37f13d63807068955c76d81104860581d61683fa35ec.png

Plot Groups State¶

fig, ax = plt.subplots()
ax.set_aspect('equal')

# Draw the mesh in the background
fv1.plot_mesh(ax=ax)

ptm1.plot(time=time, ax=ax, s=5, c='blue', stats=1, label='In Suspension')
ptm1.plot(time=time, ax=ax, s=5, c='yellow', stats=2, label='Dry')
ptm1.plot(time=time, ax=ax, s=5, c='brown', stats=3, label='Bed')

ax.legend()

plt.show()
../../../_images/a982ea5819c6bb57f46642ddf8e4cc5e473d1de1b9bd955b211ae0e2b7172ec4.png

Plot Coloured¶

We can use the color_by argument to color the particles by a variable stored in the dataset. Examples include z, age, stats, group ids, etc.

fig, ax = plt.subplots()
ax.set_aspect('equal')

# Draw the mesh in the background
fv1.plot_mesh(ax=ax)

ptm1.plot(time=time, ax=ax, s=5, color_by='z', cmap='jet')

plt.show()
../../../_images/2674cf285132df43844a43a38218456d204d26fe9dde70ea6d7eb9dea5392c64.png

Plot Highlight¶

Sometimes we just want to highlight a specific group or status. There’s a few ways we can do this, here’s a simple one if we know what group ids we have.

(You could totally just plot all particles and then overplot with the highlights too!)

fig, ax = plt.subplots()
ax.set_aspect('equal')

# Draw the mesh in the background
fv1.plot_mesh(ax=ax)

ptm1.plot(time=time, ax=ax, s=5, c='k', group_ids=(1,3,4), label='Groups 1, 3 and 4')
ptm1.plot(time=time, ax=ax, s=10, c='y', group_ids=2, label='Group 2')

ax.legend()

plt.show()
../../../_images/996d42558daa7a4ac6040608edeca48876916afb82afd75dfc1010565e349b2c.png

Plot Highlight AND Status¶

Pretty much as above but let’s highlight a specific group and status. We’ll also turn off the mesh, but keep the boundary on.

fig, ax = plt.subplots()
ax.set_aspect('equal')

# Draw the mesh in the background
fv1.plot_mesh(ax=ax, mesh=False)

ptm1.plot(time=time, ax=ax, s=5, c='grey', alpha=0.25, label='All particles')
ptm1.plot(time=time, ax=ax, s=10, c='y', group_ids=2, stats=3, label='Special Particles')

ax.legend()

plt.show()
../../../_images/85482fd536b76179bf69af7b58c4acbf4982a470f0c67b1ae060992720ec45dd.png

Grid Plots¶

The above plots are great when you have a managable set of particles, or you only want to show a single timestep.

However they quickly get bogged down when you have many many particles, such as order 100,000s to millions. In this case, grid plots are the way to go.

Pretty much all the above will still work, but you can supply plot_type=grid instead.

Plot Scatter vs Grid¶

fig, axes = plt.subplots(ncols=3, figsize=(14, 3), sharex=True, sharey=True, constrained_layout=True)
axes[0].set_title('Scatter Plot')
axes[1].set_title('Gridded Plot - Default (100x100)')
axes[2].set_title('Gridded Plot - A bit coarser (50x50)')

ptm1.plot(ax=axes[0])
ptm1.plot(plot_type='hist', ax=axes[1], colorbar_kwargs=dict(orientation='horizontal'), cmap='turbo')
ptm1.plot(plot_type='hist', ax=axes[2], colorbar_kwargs=dict(orientation='horizontal'), nx=50, ny=50, cmap='turbo')

plt.show()
../../../_images/80a4a2e4b85c58d37c25bea5ab048d1b095d7e0ad7c12e26d89c24077b0ef9f3.png

As above, but zoomed out a little more and with the mesh turned back on for reference.

fig, axes = plt.subplots(ncols=3, figsize=(10, 5), sharex=True, sharey=True, constrained_layout=True)
axes[0].set_title('Scatter')
axes[1].set_title('Gridded (100x100)')
axes[2].set_title('Gridded (50x50)')

ptm1.plot(ax=axes[0])
ptm1.plot(plot_type='hist', ax=axes[1], colorbar=False, cmap='turbo')
ptm1.plot(plot_type='hist', ax=axes[2], colorbar=False, nx=50, ny=50, cmap='turbo')

for ax in axes:
    fv1.plot_mesh(ax=ax, mesh=False)

plt.show()
../../../_images/9e06f8d968150161507213d753d6b1d87ea9a24628b1c0c4f7bd849c732e5c2f.png

Plot Variable on Grid¶

We can use the color_by argument to bin up variables and show them on the grid. This is a great way to see things like particle age, or even group or status when the particles are all mixed up

fig, axes = plt.subplots(ncols=3, figsize=(14, 3), sharex=True, sharey=True, constrained_layout=True)
axes[0].set_title('Scatter Plot')
axes[1].set_title('Gridded Plot - Default (100x100)')
axes[2].set_title('Gridded Plot - A bit coarser (50x50)')

ptm1.plot(plot_type='hist', ax=axes[0], colorbar_kwargs=dict(orientation='horizontal'), cmap='turbo', nx=50, ny=50)
ptm1.plot(plot_type='hist', color_by='age', ax=axes[1], colorbar_kwargs=dict(orientation='horizontal'), cmap='turbo', nx=50, ny=50)
ptm1.plot(plot_type='hist', color_by='groupID', ax=axes[2], colorbar_kwargs=dict(orientation='horizontal'), nx=50, ny=50, cmap='turbo')

plt.show()
../../../_images/b3c9e3785964a8c9b6a9d41c910ef62c383833e9665268596b5de17b33a07e9c.png

Plot mass on Grid¶

Some variables like mass and uvw have a third dimension that we need to reduce before we plot them.

print(ptm1['mass'].dims)
('time', 'trajectory', 'mass_consituents')

Let’s say we want to plot the total mass in a grid, across all the mass constituents. In our example case, we only have 1 mass constituent but you may sometimes have a more detailed model that contains several constituents here.

ptm1['total_mass'] = ptm1['mass'].sum(dim='mass_consituents')

Now when we plot, we also need to think about what we want to show. If we just plot the default grid, we’ll end up showing the mean mass of the particles in the grid cell; i.e., what is the mean of the mass that each particle has. But most of the time we actually want the total mass in the cell, so we need to change the statistic from mean (default) to sum.

fig, axes = plt.subplots(ncols=3, figsize=(14, 3), sharex=True, sharey=True, constrained_layout=True)
axes[0].set_title('Density')
axes[1].set_title('Mean of Total Mass Per Particle')
axes[2].set_title('Sum Of Total Mass')

ptm1.plot(plot_type='hist', ax=axes[0], colorbar_kwargs=dict(orientation='horizontal'), cmap='turbo', nx=50, ny=50)
ptm1.plot(plot_type='hist', color_by='total_mass', ax=axes[1], colorbar_kwargs=dict(orientation='horizontal'), cmap='turbo', nx=50, ny=50)
ptm1.plot(plot_type='hist', color_by='total_mass', statistic='sum', ax=axes[2], colorbar_kwargs=dict(orientation='horizontal'), cmap='turbo', nx=50, ny=50)

plt.show()
../../../_images/ae11274a1ebdd94fb64f9c4d58df37f18faadbf617fc0cdc923b2f71077f7d6f.png

Plot Interactive¶

We often want to visualise our results interactively to see if the model is behaving as we expect it to.

Similar to hydrodynamic results, we can use plot_interactive to interactively scroll through out timeseries. We need to first enable widget mode with %matplotlib widget, and then we can call the function afterwards.

Any of the options of .plot are available in the interactive mode.

Note: The example below is a static example from another model showing how the interactive mode could look like for a large result

%matplotlib widget
ptm1.plot_interactive(plot_type='hist')

Example of the widget block

Example interactive histogram figure

plt.close('all')
%matplotlib inline

This concludes the examples on particle plotting.

<Page contents

>Page contents:

  • Gallery 6: Particle Tracking Plots
    • Load Results
    • Scatter Plots
      • Plot Basic
      • Plot Groups
      • Plot Groups State
      • Plot Coloured
      • Plot Highlight
      • Plot Highlight AND Status
    • Grid Plots
      • Plot Scatter vs Grid
      • Plot Variable on Grid
      • Plot mass on Grid
      • Plot Interactive
<Gallery 5: Combined Plots
Gallery 7: Miscellaneous>
© Copyright 2024 BMT. Created using Sphinx 8.2.3.

Styled using the Piccolo Theme