Visualization options#
Different options are available to visualize a pore network. In this notebook we cover plotting in Spyder,interactive plots in Jupyter, and using Paraview software to visualize the network and simulation results.
%matplotlib inline
import os
current_directory = os.getcwd()
try:
import plotly
except ModuleNotFoundError:
!pip install plotly
Spyder#
Spyder is an open-source IDE for Python. The Plots
pane in Spyder shows generated images and plots in Console
. For more details see Spyder Plots. As an example, let’s run the following codes in Spyder’s Editor and visualize the results:
import numpy as np
import openpnm as op
op.visualization.set_mpl_style()
import matplotlib.pyplot as plt
np.random.seed(10)
We create a cubic network and visualize the network pores and throats using plot_coordinates
and plot_connections
. These functions are based on matplotlib
functions and costumized for pore network visualization. Here the pores and throats are colored by the pores and throats diameter. The throats are shown as connections in a wireframe. We used alpha
to create a more transparent color for throats:
pn = op.network.Cubic(shape=[15, 15, 15], spacing=1e-6)
pn.add_model_collection(op.models.collections.geometry.spheres_and_cylinders)
pn.regenerate_models()
ax = op.visualization.plot_coordinates(pn, color_by=pn['pore.diameter'])
ax = op.visualization.plot_connections(pn, ax=ax, color_by=pn['throat.diameter'], alpha=0.1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[3], line 3
1 pn = op.network.Cubic(shape=[15, 15, 15], spacing=1e-6)
2 pn.add_model_collection(op.models.collections.geometry.spheres_and_cylinders)
----> 3 pn.regenerate_models()
4 ax = op.visualization.plot_coordinates(pn, color_by=pn['pore.diameter'])
5 ax = op.visualization.plot_connections(pn, ax=ax, color_by=pn['throat.diameter'], alpha=0.1)
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/core/_models.py:476, in ModelsMixin2.regenerate_models(self, propnames, exclude)
474 for item in propnames:
475 try:
--> 476 self.run_model(item)
477 except KeyError as e:
478 msg = (f"{item} was not run since the following property"
479 f" is missing: {e}")
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/core/_models.py:507, in ModelsMixin2.run_model(self, propname, domain)
505 if item.startswith(propname+"@"):
506 _, _, domain = item.partition("@")
--> 507 self.run_model(propname=propname, domain=domain)
508 else: # domain was given explicitly
509 domain = domain.split('.', 1)[-1]
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/core/_models.py:521, in ModelsMixin2.run_model(self, propname, domain)
519 if 'domain' not in inspect.getfullargspec(mod_dict['model']).args:
520 _ = kwargs.pop('domain', None)
--> 521 vals = mod_dict['model'](self, **kwargs)
522 if isinstance(vals, dict): # Handle models that return a dict
523 for k, v in vals.items():
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/models/misc/_neighbor_lookups.py:123, in from_neighbor_pores(target, prop, mode, ignore_nans)
121 network = target.network
122 throats = target.Ts
--> 123 P12 = network.find_connected_pores(throats)
124 pvalues = target[prop][P12]
125 if ignore_nans:
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/network/_network.py:443, in Network.find_connected_pores(self, throats, flatten, mode)
391 r"""
392 Return a list of pores connected to the given list of throats
393
(...)
440
441 """
442 Ts = self._parse_indices(throats)
--> 443 pores = topotools.find_connected_sites(bonds=Ts, network=self,
444 flatten=flatten, logic=mode)
445 return pores
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/topotools/_graphtools.py:37, in find_connected_sites(bonds, **kwargs)
36 def find_connected_sites(bonds, **kwargs):
---> 37 return queries.find_connected_nodes(inds=bonds, **kwargs)
File /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/openpnm/_skgraph/queries/_funcs.py:167, in find_connected_nodes(network, inds, flatten, logic)
165 temp = temp.astype(float)
166 temp[inds] = np.nan
--> 167 temp = np.reshape(a=temp, newshape=[len(edges), 2], order='F')
168 neighbors = temp
169 else:
TypeError: reshape() got some positional-only arguments passed as keyword arguments: 'a'
The results from running in Spyder:
Other types of plots and examples such as histograms of data, plot coordinates and connections for extracted network, distribution of quantities in phase, etc can be generated and visualized in Spyder.
Interactive plots in Jupyter notebook#
The plots in Spyder and Jupyter notebook shown in previous examples are static. To create an interactive plot in Jupyter notebook we use Plotly Python, which is an interactive open-source library for plotting in Python. Plotly has different methods to plot data such as histogram, scatter plot, etc. When using Jupyter notebooks for pore network visualization, OpenPNM’s costumized function plot_notebook
(based on Plotly) can be used. Following shows an example. The resulting plot is interactive to (rotate, zoom, etc) and by hovering over pores their indices and coordinates will be shown in a box.
ax = op.visualization.plot_notebook(pn, node_color=pn['pore.diameter'], node_scale=10)
ax.show()
A sceenshot of the interactive plot is shown here:
Paraview#
Paraview is an open-source data analysis and visualization software. To visualize a network in Paraview, we first need to save the pore network data to a file type and format that is compatible with Paraview input file format. OpenPNM’s io
(input/output) class includes methods to export different types of data for use in different softwares. Here, we demonstrate an example of exporting the network to a vtp
file for visualizing in Paraveiw. Note that by exporting the project using project_to_vtk
method, both network and existing phases will be exported to a single vtp
file. As a visualization example, let’s apply a steady state Fickian diffusion algorithm on the generated network and find the concentration distribution on the network:
air = op.phase.Air(network=pn,name='air')
air.add_model_collection(op.models.collections.phase.air)
air.add_model_collection(op.models.collections.physics.basic)
air.regenerate_models()
inlet=pn.pores('left')
outlet=pn.pores('right')
Fd = op.algorithms.FickianDiffusion(network=pn, phase=air)
Fd.set_value_BC(pores=inlet, values=1)
Fd.set_value_BC(pores=outlet, values=0)
Fd.run()
air.update(Fd.soln)
[15:45:29] WARNING throat.entry_pressure was not run since the following _models.py:480 property is missing: 'throat.surface_tension'
Now we save the network data to a user-defined folder address and file_name. Here, we use the current directory as path_to_file
:
path_to_file = current_directory
op.io._vtk.project_to_vtk(pn.project, filename=path_to_file+'/Paraview_net')
We can now import the generated file Paraview_net.vtp
in Parview for visualization.
Import
Find the data and import
Click on Apply to visualize this settings (Click on this button after any time changes are applied for visualization)
The imported file contains the parameters computed by OpenPNM as shown in the Properties bar. To visualize pore data, we need to first create glyphs.
Click on Glyph button in the tool bar
Change pore shapes to spheres, adjust size, color, and other settings
Click on Apply to visualize this setting
Final result shows spherical pores colored and scaled by pore diameter:
To visualize the throats, we apply some filters on the originally imported object (Paraview_net). Click on Paraview_net.vtp object in Pipeline Browser. Then select following filters. Filters are available to select from Filters Tab> Alphabetical.
Apply Shrink filter with Shrink Factor=1.
Apply CellDatatoPointdata filter, which transposes cell data to the data point.
Apply ExtractSurface filter, which extracts the surface.
Apply Tube filter to plot the data as tubes, Adjust the settings for color and size of the throat
We can now visualize the throat data plotted with tubes radius proportional to throat diameter and tubes colour base on throat diameter:
To visualize both pores and throats, we select the eye icon next to the Glyph1 object. For a better visualization of sizes, we increased the Radius in Glyph1 properties from 0.5 to 0.75:
We can select other properties for visualization. To see the pore concentration values, we select a solid color for throats and select pore.concentration
for pores.
Select Tube1 object, change the coloring to a solid color
Select the Glyph1 object, change the coloring to pore concentration
(Note: We selected a solid color for throats, as we didn’t define those values before saving the vtp file. In pore-scale model calculation, if throat quantity (for example concentration) is not assigned OpenPNM by default interpolates quantity values in throats based on its connected pores.). If throat concentration is assigned to the network, we can visualize them selecting throat.concentration
in Coloring option of the Tube object.
This is the visualization result: