diff --git a/examples/2D_Interpolation.html b/examples/2D_Interpolation.html deleted file mode 100644 index b9b974fe8..000000000 --- a/examples/2D_Interpolation.html +++ /dev/null @@ -1,16157 +0,0 @@ - - - - -2D_Interpolation - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
-
-

Example - 2D Grid Interpolation

The xmsinterp library contains classes for performing 2d (x,y) linear, natural neighbor, and idw interpolation: InterpLinear and InterpIdw. Natural neighbor interpolation is performed using the linear interpolation class. 3d (x,y,z) interpolation can be performed using the idw class. Points (x,y) must be given to create the interpolation class.

-

We will learn how to use the interpolation classes by using a set of 2D points (x,y) with a measurement at each point. These points come from a csv file. Then we will generate a grid that bounds these points and use different interpolation options to visualize the data.

- -
-
-
-
-
-
In [1]:
-
-
-
import param
-import panel as pn
-import holoviews as hv
-import numpy as np
-import pandas as pd
-import xarray as xr
-import hvplot.pandas
-import hvplot.xarray
-from holoviews.streams import Params
-
-from xms import interp
-
- -
-
-
- -
-
- - -
- -
- - - - - -
-
- -
- -
- -
- -
- - - -
- - - - - -
- -
- -
- -
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
In [2]:
-
-
-
# read in the data to do the interpolation
-# drop the id columns from the data frame so we can pass the remaining data as points to the interp class
-df = pd.read_csv("plumedat.csv").drop(['id'], axis=1)
-df.hvplot.scatter(x='x', y='y', c='c', height=600, cmap='jet', size=120, colorbar=True)
-
- -
-
-
- -
-
- - -
- -
Out[2]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Generate grid for visualization

Get the min, max (x, y) of the data and generate a grid of points.

- -
-
-
-
-
-
In [3]:
-
-
-
# get the (x,y) range of the data and expand by 10%
-def buffer_range(range_min, range_max, buf_by=0.1):
-    buf = (range_max - range_min) * buf_by
-    return (range_min - buf, range_max + buf)
-
-x_range = buffer_range(df.x.min(), df.x.max())
-y_range = buffer_range(df.y.min(), df.y.max())
-
-# adjust these values for a higher/lower resolution grid
-number_of_x_points=600
-number_of_y_points=400
-x = np.linspace(x_range[0], x_range[1], number_of_x_points)
-y = np.linspace(y_range[0], y_range[1], number_of_y_points)
-grid = np.meshgrid(x, y)
-pts = np.stack([i.flatten() for i in grid], axis=1)
-
- -
-
-
- -
-
-
-
-

Interpolate to the grid using linear interpolation and display the results with matplotlib.

- -
-
-
-
-
-
In [4]:
-
-
-
linear = interp.interpolate.InterpLinear(df.values)
-z = linear.interpolate_to_points(pts)
-# I would prefer to be able to set up an interpolator like this:
-# linear = interp.Interpolator(kind='linear', values=df.values)
-zz = np.reshape(z, (len(y), len(x)))
-xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-xa.hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
- - -
- -
Out[4]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Interpolate using natural neighbor. The first example shows a "constant" nodal function and the second example shows a "quadratic" nodals function. A nodal function can better model trends that exist in the measured values.

- -
-
-
-
-
-
In [5]:
-
-
-
linear.set_use_natural_neighbor(on=True)
-z = linear.interpolate_to_points(pts)
-# z = linear.interpolate_to_points(pts, use='natural_neighbor')
-zz = np.reshape(z, (len(y), len(x)))
-xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-xa.hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
- - -
- -
Out[5]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Now do natural neighbor with a quadratic nodal function.

- -
-
-
-
-
-
In [6]:
-
-
-
linear.set_use_natural_neighbor(on=True, nodal_function_type="quadratic", 
-                                nodal_function_point_search_option="nearest_points")
-z = linear.interpolate_to_points(pts)
-# z = linear.interp_to_pts(pts, use='natural_neighbor', nodal_func_type='quadratic', nd_func_pt_search_opt='nearest_pts')
-zz = np.reshape(z, (len(y), len(x)))
-xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-xa.hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
- - -
- -
Out[6]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Now we will use Inverse Distance Weighted (IDW) to interpolate to the grid. Notice that unlike Linear and Natural Neighbor interpolation, IDW interpolation can extrapolate beyond the bounds of the input data points.

- -
-
-
-
-
-
In [7]:
-
-
-
idw = interp.interpolate.InterpIdw(df.values)
-z = idw.interpolate_to_points(pts)
-# idw = interp.Interpolator(kind='idw', values=df.values)
-# z = idw.interpolate_to_points(pts)
-zz = np.reshape(z, (len(y), len(x)))
-xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-xa.hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
- - -
- -
Out[7]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Now interpolate using a nodal function to try to better capture trends in the data set.

- -
-
-
-
-
-
In [8]:
-
-
-
idw.set_nodal_function(nodal_function_type="gradient_plane")
-z = idw.interpolate_to_points(pts)
-# z = idw.interp_to_pts(pts, nodal_func_type='gradient_plane')
-zz = np.reshape(z, (len(y), len(x)))
-xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-xa.hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
- - -
- -
Out[8]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Notice, in the previous interpolation that we get negative values in some locations. If we assume that there should be no negatives values (like when measuring concentration) we can use the truncation options to adjust the interpolation.

- -
-
-
-
-
-
In [9]:
-
-
-
idw.set_truncation(maximum=150, minimum=0)
-z = idw.interpolate_to_points(pts)
-# z = idw.interpolate_to_points(pts, smax=150, smin=0)
-zz = np.reshape(z, (len(y), len(x)))
-xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-xa.hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
- - -
- -
Out[9]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
-

Interactive interpolation using param, holoviews, and panel

Below we define a param class for the interpolation options. Then we use panel to show widgets and a dynamic plot. The user can change the widget values and then push the "Compute new plot" button to update the plot using the currently specified interpolation options.

- -
-
-
-
-
-
In [10]:
-
-
-
class InterpOptions(param.Parameterized):
-    interpolation_option = param.ObjectSelector(default='idw', objects=['linear', 'natural_neighbor', 'idw'],
-                                                precedence=1)
-    nodal_function = param.ObjectSelector(default='constant', objects=['constant', 'gradient_plane', 'quadratic'],
-                                          precedence=1.1)
-    truncation = param.Boolean(default=True, precedence=2)
-    truncation_maximum = param.Number(default=df.loc[df['c'].idxmax()]['c'], precedence=2.1)
-    truncation_minimum = param.Number(default=df.loc[df['c'].idxmin()]['c'], precedence=2.2)
-    
-    @param.depends('interpolation_option', watch=True)
-    def _update_nodal_function(self):
-        if self.interpolation_option == 'linear':
-            self.params('nodal_function').precedence = -1
-        else:
-            self.params('nodal_function').precedence = 1.1
-
-    @param.depends('truncation', watch=True)
-    def _update_truncation_opts(self):
-        if self.truncation:
-            self.params('truncation_maximum').precedence = 2.1
-            self.params('truncation_minimum').precedence = 2.2
-        else:
-            self.params('truncation_maximum').precedence = -1
-            self.params('truncation_minimum').precedence = -1
-    
-    def generate_zz(self):
-        # Get Interp Object
-        interp_object = None
-        if self.interpolation_option != 'idw':
-            #interp_object = linear
-            interp_object = interp.interpolate.InterpLinear(points=df.values)
-            if self.interpolation_option == 'natural_neighbor':
-                interp_object.set_use_natural_neighbor(on=True, nodal_function_type=self.nodal_function,
-                                                       nodal_function_point_search_option="nearest_points")
-        else:
-            interp_object = interp.interpolate.InterpIdw(points=df.values)
-            interp_object.set_nodal_function(nodal_function_type=self.nodal_function)
-
-        if self.truncation:
-            interp_object.set_truncation(self.truncation_maximum, self.truncation_minimum)
-        z = interp_object.interpolate_to_points(pts)
-        zz = np.reshape(z, (len(y), len(x)))
-        xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)
-        return xa
-        
-    def get_image(self, *args, **kwargs):
-        return self.generate_zz().hvplot(x='x', y='y', height=500, cmap='viridis')
-
- -
-
-
- -
-
-
-
In [11]:
-
-
-
opts = InterpOptions(name="")
-dmap = hv.util.Dynamic(opts.get_image(), operation=opts.get_image, streams=[Params(opts)])
-pn.Row(opts, dmap)
-
- -
-
-
- -
-
- - -
- -
- - -
-
WARNING:param.: The Parameterized instance has instance parameters created using new-style param APIs, which are incompatible with .params. Use the new more explicit APIs on the .param accessor to query parameter instances.To query all parameter instances use .param.objects with the option to return either class or instance parameter objects. Alternatively use .param[name] indexing to access a specific parameter object by name.
-
-
-
- -
- -
Out[11]:
- - - -
-
- - - - - -
-
- -
- -
- -
-
- -
-
-
-
In [ ]:
-
-
-
 
-
- -
-
-
- -
-
-
-
In [ ]:
-
-
-
 
-
- -
-
-
- -
-
-
-
In [ ]:
-
-
-
 
-
- -
-
-
- -
-
-
- - - - - - diff --git a/examples/2D_Interpolation.zip b/examples/2D_Interpolation.zip deleted file mode 100644 index a45c9c7ce..000000000 Binary files a/examples/2D_Interpolation.zip and /dev/null differ diff --git a/examples/2D_Interpolation/2D_Interpolation.ipynb b/examples/2D_Interpolation/2D_Interpolation.ipynb new file mode 100644 index 000000000..79044e26a --- /dev/null +++ b/examples/2D_Interpolation/2D_Interpolation.ipynb @@ -0,0 +1,2363 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Table of Contents" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- [Interpolation](#Interpolation)\n", + "\n", + "- [Linear Interpolation (InterpLinear)](#Linear-Interpolation-(InterpLinear))\n", + " - [set_points_and_triangles() Method](#set_points_and_triangles()-Method)\n", + " - [set_use_natural_neighbor() Method](#set_use_natural_neighbor()-Method)\n", + " - [scalars Property](#scalars-Property)\n", + " - [interpolate_to_point() Method](#interpolate_to_point()-Method)\n", + " - [interpolate_to_points()Method](#interpolate_to_points()-Method)\n", + " - [set_truncation(), truncate_min, truncate_max, and truncate_interpolated_values](#set_truncation(),-truncate_min,-truncate_max,-and-truncate_interpolated_values)\n", + " - [point_activity Property](#point_activity-Property)\n", + " - [triangle_activity Property](#triangle_activity-Property)\n", + " - [extrapolation_point_indexes Property](#extrapolation_point_indexes-Property)\n", + " - [triangle_containing_point() Method](#triangle_containing_point()-Method)\n", + " - [triangle_envelopes_containing_point() Method](#triangle_envelopes_containing_point()-Method)\n", + " - [interpolate_weights() Method](#interpolate_weights()-Method)\n", + " - [extrapolation_value Property](#extrapolation_value-Property)\n", + " - [set_use_clough_tocher() Method](#set_use_clough_tocher()-Method)\n", + " \n", + "- [Inverse Distance Weighted Interpolation (InterpIdw)](#Inverse-Distance-Weighted-Interpolation-(InterpIdw))\n", + " - [Truncation](#Truncation)\n", + " - [set_points() Method](#set_points()-Method)\n", + " - [points Property](#points-Property)\n", + " - [scalars Property](#idw_scalars)\n", + " - [interpolate_to_point() Method](#idw_interpolate_to_point)\n", + " - [interpolate_to_points() Method](#idw_interpolate_to_points)\n", + " - [set_nodal_function() Method](#set_nodal_function()-Method)\n", + " - [weight_calculation_method Property](#weight_calculation_method-Property)\n", + " - [power Property](#power-Property)\n", + " - [set_search_options() Method](#set_search_options()-Method)\n", + " - [search_options_use_quadrant_search Property](#search_options_use_quadrant_search-Property)\n", + " - [nodal_function_number_nearest_points Property](#nodal_function_number_nearest_points-Property)\n", + " - [point_activity Property](#idw_point_activity)\n", + " - [interpolate_weights_method Property](#idw_interpolate_weights_method)\n", + " \n", + "- [InterpLinearExtrapIdw](#InterpLinearExtrapIdw)\n", + " - [InterpLinearExtrapIdw Methods and Properties](#InterpLinearExtrapIdw-Methods-and-Properties)\n", + " - [set_idw_nodal_function() Method](#set_idw_nodal_function()-Method)\n", + " - [set_idw_search_options() Method](#set_idw_search_options()-Method)\n", + " \n", + "- [InterpAnisotropic](#InterpAnisotropic)\n", + " - [InterpAnisotropic.set_points()](#InterpAnisotropic.set_points())\n", + " - [set_x_scale() Method](#set_x_scale()-Method)\n", + " - [set_power() Method](#set_power()-Method)\n", + " - [interp_to_point() Method](#interp_to_point()-Method)\n", + " - [interp_to_points() Method](#interp_to_points()-Method)\n", + " - [get_interpolation_points() Method](#get_interpolation_points()-Method)\n", + " - [get_transformed_points() Method](#get_transformed_points()-Method)\n", + " \n", + "- [Convenience Methods](#Convenience-Methods)\n", + " - [interpolate_to_points() Method](#convenience_interpolate_to_points)\n", + "\n", + "- [Example - 2D Grid Interpolation](#Example---2D-Grid-Interpolation)\n", + " - [Generate grid for visualization](#Generate-grid-for-visualization)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Interpolation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When using xmsinterp to interpolate a scatter dataset there are a few steps in general to follow. These steps are shown below.\n", + "\n", + "- Get the scatter point data that we will interpolate.\n", + "- Get the points/grid that we will interpolate to.\n", + "- Setup any additional parameters.\n", + "- Interpolate the data.\n", + "\n", + "The different methods of interpolation that can be done with xmsinterp are demonstrated in the following sections. The final section, [Example - 2D Grid Interpolation](#Example---2D-Grid-Interpolation), shows some examples of interpolation with some more realistic data. For more info on interpolation see the xmswiki." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linear Interpolation (InterpLinear)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Linear interpolation scheme uses data points that are first triangulated to form a network of triangles. The network of triangles only covers the convex hull of the point data, making extrapolation beyond the convex hull not possible. To perform linear interpolation we use a `InterpLinear` object. The constructor of the `InterpLinear` object takes the following arguments:\n", + "\n", + "- `points` (list): The points of the source geometry as x,y,z tuples.\n", + "- `triangles` (list): The triangles of the source geometry as point index tuples.\n", + "- `scalars` (list): The scalar values at the points.\n", + "- `nodal_function` (str): The nodal function to use One of: 'constant', 'gradient_plane', 'quadratic'.\n", + "- `point_search_option` (str): The point search option. One of: 'natural_neighbor', 'nearest_points'.\n", + "- `number_nearest_points` (int): The number of nearest points to consider.\n", + "- `blend_weights` (bool): True if weights should be blended.\n", + "- `progress` (Observer): Observer object for providing feedback.\n", + "\n", + "The only required argument is `points`, with all the other arguments having default values. Creation of an InterpLinear object is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Import needed for InterpLinear\n", + "from xms.interp.interpolate.interp_linear import InterpLinear\n", + "\n", + "# Create an InterpLinear object\n", + "interper = InterpLinear(points=[(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using InterpLinear's properties, we can see that even though we didn't pass values for the constructor's other arguments, values for triangles and scalars were automatically determined." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "triangles: [3 0 1 1 2 3]\n", + "scalars: [0. 1. 2. 3.]\n" + ] + } + ], + "source": [ + "print(f'triangles: {interper.triangles}')\n", + "print(f'scalars: {interper.scalars}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we'll need to create the points/bounding grid that our scatter dataset will interpolate to. These will be x,y,z tuples stored in an iterable." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "points = ((2, 1, 0), (5, 10, 2.5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we will interpolate our data using the `interpolate_to_points()` method." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.5, 2.5)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The return value will be a tuple holding a value for each point that was in the iterable passed to `interpolate_to_points()`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_points_and_triangles() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The points and triangles can alternatively be set with the `set_points_and_triangles()` method. The following arguments are accepted:\n", + "\n", + "- `points` (iterable): Array of point locations.\n", + "- `triangles` (iterable): Array of triangles that references the points array.\n", + "\n", + "The array passed as the triangle argument must have a size that is a multiple of 3. The first 3 locations in the array represent the first triangle and will have indices that correspond to locations in the points array. The usage of this method is shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.5, 2.5)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_points_and_triangles(points=[(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)], triangles=[3, 0, 1, 1, 2, 3])\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_use_natural_neighbor() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we want to interpolate using Natural Neighbor we can use the `set_use_natural_neighbor()` method. This method takes the following arguments:\n", + "\n", + "- `on` (bool): Indicate if Natural Neighbor should be used.\n", + "- `nodal_function` (str): Indicates which nodal function to use. One of 'constant', 'gradient_plane', or 'quadratic'.\n", + "- `point_search_option` (str): Indicates options for the nearest points when computing the nodal functions. One of 'natural_neighbor', or 'nearest_points'.\n", + "- `number_nearest_points` (int): The number of nearest points for nodal function computation.\n", + "- `blend_weights` (bool): Option to use a blending function on the calculated weights.\n", + "- `progress` (observer): Progress bar to give user feedback for generation of the nodal functions.\n", + "\n", + "All of these arguments are optional and will be given default values when no values are passed to them." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.1559019237756729, 2.5)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_use_natural_neighbor(on=True, nodal_function='constant')\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### scalars Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `scalars` property can be used to set the values that will be interpolated from. It takes an iterable whose length should be equal to the number of points passed to either the constructor of `InterpLinear`, or the number of points passed to `set_points_and_triangles()` method. The usage of this property is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "interper.scalars = [1.0, 3.4, 2.0, 4.0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### interpolate_to_point() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_to_point()` method uses the stored triangles to interpolate to the given point. It takes tuple of three values for the point to interpolate to, and returns the interpolated value at the given point. If the given point is outside the stored triangles (extrapolation) then the `extrapolation_value` is returned." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.1299608945846558\n", + "-9999.0\n" + ] + } + ], + "source": [ + "# interpolate to a point inside the stored triangles\n", + "print(f'{interper.interpolate_to_point((1.0, 1.0, 0.0))}')\n", + "\n", + "# interpolate to a point outside the stored triangles (extrapolation). extrapolation_value is returned\n", + "interper.extrapolation_value = -9999\n", + "print(f'{interper.interpolate_to_point((100, 100, 100))}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### interpolate_to_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_to_points()` method is the same as `interpolate_to_point()`, except it can be passed multiple points." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.1299608945846558, 1.4432363510131836, -9999.0)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.interpolate_to_points([(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (100, 100, 100)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_truncation(), truncate_min, truncate_max, and truncate_interpolated_values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At times it can be desirable to limit the results to a certain range. This can be done with the `set_truncation(maximum,minimum)` method." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.2856812477111816, 3.0)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_truncation(minimum=0, maximum=3)\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can see what truncation values are set with the `truncate_min` and `truncate_max` properties. The `truncate_interpolated_values` property will tell you if the results are being truncated." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "truncate_min: 0.0\n", + "truncate_max: 3.0\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(f'truncate_min: {interper.truncate_min}')\n", + "print(f'truncate_max: {interper.truncate_max}')\n", + "interper.truncate_interpolated_values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### point_activity Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `point_activity` property can be used to get/set the activity of the points being interpolated from. It takes an iterable whose length is the number of points being interpolated from. The values represent the activity of the point with the corresponding index." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 1, 0, 1], dtype=uint8)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.point_activity = (True, True, False, True)\n", + "\n", + "interper.point_activity" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### triangle_activity Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `triangle_activity` property can be used to get/set the activity of the triangles being interpolated from. It takes an iterable whose length is the number of triangles being interpolated from. The values represent the activity of the triangle with the corresponding index." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 1], dtype=uint8)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.triangle_activity = (True, True)\n", + "\n", + "interper.triangle_activity" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "#### extrapolation_point_indexes Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `extrapolation_point_indexes` property returns a list of indexes for the points that were outside all of the stored triangles. The points that are considered are the points that were passed to the `interpolate_to_points()` method. Usage of this property is illustrated below." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0, 3])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The points at index 0 and 3 are outside the stored triangles\n", + "interper.interpolate_to_points([(500, 500, 500), (1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (100, 100, 100)])\n", + "\n", + "interper.extrapolation_point_indexes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### triangle_containing_point() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `triangle_containing_point()` method returns the index of the stored triangle that the given point is located in. If none of the triangles contain the point then `-1` is returned." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "-1\n" + ] + } + ], + "source": [ + "# Passing a point that does lie inside a stored triangle\n", + "print(interper.triangle_containing_point((1.0,1.5,1.0)))\n", + "\n", + "# Passing a point that DOES NOT lie inside a stored triangle\n", + "print(interper.triangle_containing_point((100,100,100)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### triangle_envelopes_containing_point() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `triangle_envelopes_containing_point()` Method returns a list of the indexes of the stored triangles that the given point is located in. If none of the triangles contain the point then an empty list is returned." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 3]\n", + "[]\n" + ] + } + ], + "source": [ + "# Passing a point that does lie inside a stored triangle\n", + "print(interper.triangle_envelopes_containing_point((1.0,1.5,1.0)))\n", + "\n", + "# Passing a point that DOES NOT lie inside a stored triangle\n", + "print(interper.triangle_envelopes_containing_point((100,100,100)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### interpolate_weights() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_weights()` method takes a point and uses the stored triangles to get the interpolation weights for the given point. A tuple containing three entries is returned. The first entry is a bool indicating whether or not the point was inside the stored triangles. The second entry is a list containing the indexes of the stored points whose weights were interpolated. The third entry contains a list of the weights for the point's whose indexes were in the list of the second entry. In the case that the first entry is `False`, both the lists in the second and third entry will be empty." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(True, array([3, 0, 1]), array([0.1, 0.8, 0.1]))\n", + "(False, array([], dtype=int32), array([], dtype=float64))\n" + ] + } + ], + "source": [ + "# Passing a point that lies inside the stored triangles\n", + "r1 = interper.interpolate_weights((1,1,1))\n", + "\n", + "# Passing a point that DOES NOT lie inside the stored triangles\n", + "r2 = interper.interpolate_weights((100,100,100))\n", + "\n", + "print(r1)\n", + "print(r2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### extrapolation_value Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `extrapolation_value` property can be used to set what value is returned when the object attempts to interpolate outside the stored triangles. Linear interpolation cannot extrapolate beyond the convex hull formed by the stored triangles, instead the `extrapolation_value` is returned in the case extrapolation is attempted." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "interper.extrapolation_value = -9999" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_use_clough_tocher() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_use_clough_tocher()` method allows you to tell the `InterpLinear` object to use the Clough Tocher method of interpolation. It takes two arguments which are shown below:\n", + "\n", + "- `on` (bool): Whether or not clough tocher interpolation should be used.\n", + "- `progress` (observer): Progress bar to give users feed back on the set up process of CT. If you have a really large set of triangles this may take some time.\n", + "\n", + "This is a legacy feature from GMS. Its usage is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.16200000047683716" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_use_clough_tocher(on=True)\n", + "\n", + "ret = interper.interpolate_to_point((1.0, 1.0, 1.0))\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inverse Distance Weighted Interpolation (InterpIdw)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Inverse Distance Weighted (IDW) is one of the most commonly used techniques for interpolation of point data. Its methods are based on the assumption that the interpolating surface should be influenced most by the nearby points and less by the more distant points. To perform inverse distance weighted interpolation, we use a `InterpIdw` object. The `InterpIdw` constructor takes the following arguments.\n", + "\n", + "- `points` (list): The points of the source geometry as x,y,z tuples.\n", + "- `scalars` (list): The scalar values at the points.\n", + "- `nodal_function` (str): The nodal function to use One of: 'constant', 'gradient_plane', 'quadratic'.\n", + "- `number_nearest_points` (int): The number of nearest points to consider.\n", + "- `quadrant_oct` (bool): True if quadrant search should be used.\n", + "- `progress` (Observer): Observer object for providing feedback.\n", + "- `is_2d` (bool): flag for 2d vs 3d interpolation.\n", + "- `weight_number_nearest_points` (int): number of points to include in interpolation weight calculation.\n", + "- `weight_quadrant_oct` (bool): get nearest points from quadrants for weight calculation.\n", + "\n", + "All arguments are optional except for points. The code to create a simple `InterpIdw` object is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Import needed for InterpIdw\n", + "from xms.interp.interpolate.interp_idw import InterpIdw\n", + "\n", + "# Create an InterpIdw object\n", + "interper = InterpIdw(points=[(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)], scalars=[1, 2, 3, 4])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "Next we'll need to create the points/bounding grid that our scatter dataset will interpolate to. These will be x,y,z tuples stored in an iterable." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "points = ((2, 1, 0), (5, 10, 2.5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can pass `points` to `interpolate_to_points()` to run IDW interpolation." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0268155336380005, 3.5)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For more information on `interpolate_to_points()` see its section below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Truncation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At times it can be desirable to limit the results to a certain range. This can be done with the `set_truncation(maximum,minimum)` method." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0268155336380005, 3.0)" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_truncation(minimum=0, maximum=3)\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can see what truncation values are set with the `truncate_min`, `truncate_max`, and `truncate_interpolation_values` properties." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "truncate_min: 0.0\n", + "truncate_max: 3.0\n", + "truncate_interpolation_values: True\n" + ] + } + ], + "source": [ + "print(f'truncate_min: {interper.truncate_min}')\n", + "print(f'truncate_max: {interper.truncate_max}')\n", + "print(f'truncate_interpolation_values: {interper.truncate_interpolation_values}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_points(points, is_2d)` method can be used to set the points being interpolated from outside the constructor. It takes the following two arguments:\n", + "\n", + "- `points` (iterable): Array of point locations.\n", + "- `is_2d` (bool): Flag if this is 2D.\n", + "\n", + "Usage of this method is illustrated below." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0224628448486328, 3.0)" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_points([(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)], False)\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### points Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `points` property can be used to retrieve the points that are being interpolated from." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0., 0., 0.],\n", + " [10., 0., 1.],\n", + " [10., 10., 2.],\n", + " [ 0., 10., 3.]])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.points" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### scalars Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `scalars` property can be used to set the values that will be interpolated from. It takes an iterable whose length should be equal to the number of points passed to either the constructor of `InterpIdw`, or the number of points passed to the `set_points()` method. The usage of this property is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "interper.scalars = [1.0, 3.4, 2.0, 4.0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### interpolate_to_point() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_to_point(point)` method interpolates to the given point. It takes tuple of three values for the point to interpolate to, and returns the interpolated value at the given point." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1.011813759803772" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.interpolate_to_point((1.0, 1.0, 0.0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### interpolate_to_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_to_points()` method is the same as [`interpolate_to_point()`](#idw_interpolate_to_point), except it can be passed multiple points." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0202679634094238, 1.1311293840408325, 2.617445468902588)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.interpolate_to_points([(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (100, 100, 100)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_nodal_function() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "IDW interpolation has many options that can be customized through the properties and methods of the `InterpIdw` class. The type of nodal function to be used can be set with the `set_nodal_function()` method. A nodal function is a plane or quadratic function that is forced to pass through the scatter point and approximate the nearby scatter points in a least squares sense. `set_nodal_function()` accepts the following arguments:\n", + "\n", + "- `nodal_function` (string): The nodal function methodology: 'constant' (0), 'gradient_plane' (1), 'quadratic' (2).\n", + "- `number_nearest_points` (int): The nearest number of points to use when calculating the nodal functions.\n", + "- `quadrant_oct` (bool): Find the nearest number of points in each quadrant (2d) or octant (3d) when computing nodal functions.\n", + "- `progress` (Observer): Progress bar to give user feedback." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0399633646011353, 3.0)" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_nodal_function(nodal_function='quadratic', number_nearest_points=16, quadrant_oct=False)\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### weight_calculation_method Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The weight calculation method can be set with the `weight_calculation_method` property. The value of this property determines how the weights for each point are calculated. The valid values for this property are either `'classic'` or `'modified'`. The classic option uses 1/distance^exponent. The modified method uses another formulation based on the distance of the furtherest location from the interpolation point." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.3225356340408325, 2.872264862060547)" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.weight_calculation_method = 'classic'\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### power Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default the class does inverse distance squared weighting, but the exponent can be changed to any value with the `power` property." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0231636762619019, 2.9719362258911133)" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.power = 4\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_search_options() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can use the `set_search_options()` method to set how to find the nearest points to the interpolation point. `set_search_options()` accepts the following arguments:\n", + "\n", + "- `nearest_point` (int): The number of nearest points to the interpolation point. These points are used to do the interpolation.\n", + "- `quadrant_oct_search` (bool): Specifies if the search criterion should find the nearest points in each quadrant (2d) or octant (3d)\n", + "\n", + "Usage of this method is shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1.0231636762619019, 2.9719362258911133)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_search_options(16, True)\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### search_options_use_quadrant_search Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `search_options_use_quadrant_search` property will return `True` if the search criterion is set to find the nearest points in each quadrant (2d). It will return `False` if the search criterion is set to find the nearest points in each octant (3d)." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "interper.set_search_options(nearest_point=16, quadrant_oct_search=False)\n", + "print(interper.search_options_use_quadrant_search)\n", + "\n", + "interper.set_search_options(nearest_point=16, quadrant_oct_search=True)\n", + "print(interper.search_options_use_quadrant_search)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### nodal_function_number_nearest_points Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `nodal_function_number_nearest_points` property returns the nodal function number nearest the points." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "16" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.nodal_function_number_nearest_points" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### point_activity Property" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `point_activity` property can be used to get/set the activity of the points being interpolated from. It takes an iterable whose length is the number of points being interpolated from. The values represent the activity of the point with the corresponding index." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + ">" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.point_activity = (True, True, False, True)\n", + "\n", + "interper.point_activity" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### interpolate_weights() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_weights()` method takes a point and gets the interpolation weights for the given point. A tuple containing two entries is returned. The first entry is a list containing the indexes of the stored points whose weights were interpolated. The second entry contains a list of the weights for the point's whose indexes were in the list of the second entry." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([0, 1, 3]), array([0.99745115, 0.00133508, 0.00121377]))" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.interpolate_weights((1,1,1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# InterpLinearExtrapIdw" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `InterpLinearExtrapIdw` class is a combination of both the `InterpLinear` class and the `InterpIdw` class. It uses Linear Interpolation when interpolating, and Inverse Distance Weighted interpolation when extrapolating. The code below illustrates this with a simple example. " + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "InterpLinear\n", + "0.4000000059604645\n", + "nan\n", + "\n", + "InterpIdw\n", + "0.010227557271718979\n", + "2.0\n", + "\n", + "InterpLinearExtrapIdw\n", + "0.4000000059604645\n", + "2.0\n" + ] + } + ], + "source": [ + "# Import needed for InterpLinearExtrapIdw\n", + "from xms.interp.interpolate.interp_linear_extrap_idw import InterpLinearExtrapIdw\n", + "\n", + "# Interpolating and extrapolating with InterpLinear. When extrapolating, the extrapolation_value is returned.\n", + "print('InterpLinear')\n", + "interperLinear = InterpLinear(points=[(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)])\n", + "print(interperLinear.interpolate_to_point((1, 1, 1)))\n", + "print(interperLinear.interpolate_to_point((100, 100, 100)))\n", + "\n", + "# Interpolating and extrapolating with InterpIdw. When extrapolating, an actual prediction is returned.\n", + "print('\\nInterpIdw')\n", + "interperIdw = InterpIdw(points=[(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)])\n", + "print(interperIdw.interpolate_to_point((1, 1, 1)))\n", + "print(interperIdw.interpolate_to_point((100, 100, 100)))\n", + "\n", + "# Interpolating and extrapolating with InterpLinearExtrapIdw. When extrapolating, an actual prediction is returned.\n", + "print('\\nInterpLinearExtrapIdw')\n", + "interper = InterpLinearExtrapIdw(points=[(0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3)])\n", + "print(interper.interpolate_to_point((1, 1, 1)))\n", + "print(interper.interpolate_to_point((100, 100, 100)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### InterpLinearExtrapIdw Methods and Properties" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`InterpLinearExtrapIdw` shares many methods and properties with both `InterpLinear` and `InterpIdw`. For information on how to use these methods and properties, see the Linear Interpolation section and the Inverse Distance Weighted Interpolation section. The sections below touch on a few methods that have been renamed in the `InterpLinearExtrapIdw` class." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_idw_nodal_function() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_idw_nodal_function()` method allows you to set the type of nodal function as well as the options for computing nodal functions. These options are for when inverse distance weighting interpolation is used. It is the same method as `set_nodal_function()` in the `InterpIdw` class. See `set_nodal_function()` for more info on nodal functions. The `set_idw_nodal_function()` method takes four arguments which are listed below.\n", + "\n", + "- `nodal_function` (string): The nodal function methodology: 'constant' (0), 'gradient_plane' (1), 'quadratic' (2).\n", + "- `number_nearest_points` (int): The nearest number of points to use when calculating the nodal functions.\n", + "- `quadrant_oct` (bool): Find the nearest number of points in each quadrant (2d) or octant (3d) when computing nodal functions.\n", + "- `progress` (Observer): Progress bar to give user feedback.\n", + "\n", + "An example of its usage is given below." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.5, 2.5)" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_idw_nodal_function(nodal_function='quadratic', number_nearest_points=16, quadrant_oct=False)\n", + "\n", + "ret = interper.interpolate_to_points(points=[(2, 1, 0), (5, 10, 2.5)])\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_idw_search_options() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_idw_search_options()` method allows you to set the search options for how to find the nearest points to the interpolation point. These options are for when inverse distance weighting interpolation is used. It is the same method as `set_search_options()` in the `InterpIdw` class. It takes the two arguments listed below.\n", + "\n", + "- `nearest_point` (int): The number of nearest points to the interpolation point. These points are used to do the interpolation.\n", + "- `quadrant_oct_search` (bool): Specifies if the search criterion should find the nearest points in each quadrant (2d) or octant (3d).\n", + "\n", + "A simple example on how to use this method is shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.5, 2.5)" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.set_idw_search_options(16, True)\n", + "\n", + "ret = interper.interpolate_to_points(points)\n", + "ret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# InterpAnisotropic" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sometimes the data associated with a scatter point set will have directional tendencies. Anisotropic interpolation allows us to take these tendencies into account. Anisotropic interpolation is actually inverse distance weighting interpolation with some extra steps. To perform anisotropic interpolation we use an `InterpAnisotropic` object. The `InterpAnisotropic` constructor does not take any arguments and can be called like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "# Import needed for InterpAnisotropic\n", + "from xms.interp.interpolate.interp_anisotropic import InterpAnisotropic\n", + "\n", + "# Create an InterpAnisotropic object\n", + "interper = InterpAnisotropic()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### set_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_points()` method is used to set both the points to be interpolated from, and the points that make up the center line. It takes three arguments which are listed below:\n", + "\n", + "- `center_line_points` (iterable): Points that make the centerline.\n", + "- `interpolation_points` (iterable): Points that will be used to interpolate from.\n", + "- `pick_closest` (bool): If true, only keep one transformed interpolation point (that is closest to the centerline).\n", + "\n", + "Below is an example that uses `set_points()`." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "# Create the centerline points. The segments of this polyline will be mapped\n", + "# onto the x-axis. The total length will be preserved.\n", + "\n", + "centerline = [[0, 0, 0], [20, 0, 0], [40, 20, 0], [60, 20, 0]]\n", + "\n", + "# Create the points used to interpolate. These points are typically taken\n", + "# from cross sections across the center line. These points will be\n", + "# transformed so that the x-coordinate corresponds to the intersection of a\n", + "# line through the point and perpendicular to a segment of the centerline.\n", + "# The y coordinate will be the distance above or below that intersection.\n", + "# Note that a single point may project onto several segments, generating\n", + "# multiple transformed points.\n", + "\n", + "interpolation_points = [\n", + " # cross-section 1\n", + " [0, 10, 100],\n", + " [0, -10, 100],\n", + " # cross-section 2\n", + " [10, 10, 90],\n", + " [10, 5, 60],\n", + " [10, 0, 50],\n", + " [10, -5, 70],\n", + " [10, -10, 90],\n", + " # cross-section 3\n", + " [20, 20, 80],\n", + " [30, 10, 40],\n", + " [40, 0, 80],\n", + " # cross-section 4\n", + " [30, 40, 70],\n", + " [35, 30, 50],\n", + " [40, 20, 30],\n", + " [45, 10, 70],\n", + " # cross-section 5\n", + " [60, 30, 50],\n", + " [60, 10, 50]]\n", + "\n", + "# Set the centerline and interpolation points used by the interpolator.\n", + "# Any point may project onto several segments of the centerline. You can use\n", + "# all such transformed points or set pick_closest to true to use only the\n", + "# one nearest the centerline.\n", + "\n", + "interper.set_points(centerline, interpolation_points, pick_closest=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_x_scale() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_x_scale()` method allows you to scale the points in the x direction. The default x scale factor is 1. Setting the scale to a value less than 1 will compress the x values, thus giving them more weight than y. Setting the scale to a value greater than 1 will result in the opposite effect." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "# Set the x scale to 0.5, thus compressing the x values.\n", + "interper.set_x_scale(0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### set_power() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `set_power()` method allows you to set the exponent of the inverse distance weight. It takes one argument which is the exponent used to compute the point weights. This method fills the same role as the `set_power` property in the `InterpIdw` class." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "# Set the exponent of the inverse distance weight to a value over 1 to dilute\n", + "# the influence of interpolation points far from the point in question.\n", + "interper.set_power(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### interp_to_point() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interp_to_point(point)` method interpolates to the given point. It takes tuple of three values for the point to interpolate to, and returns the interpolated value at the given point." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "59.53133773803711" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.interp_to_point((20, 5, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### interp_to_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interp_to_points()` method is the same as `interp_to_point()`, except it can be passed multiple points." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(64.61399841308594,\n", + " 54.390106201171875,\n", + " 71.97010803222656,\n", + " 59.53133773803711,\n", + " 58.46803283691406,\n", + " 68.09170532226562,\n", + " 81.6883544921875,\n", + " 76.03239440917969,\n", + " 53.13092803955078,\n", + " 35.41265106201172,\n", + " 40.45703125,\n", + " 50.83898162841797,\n", + " -9999999.0,\n", + " -9999999.0)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Interpolate to several locations. Note that the last\n", + "# two points are beyond the range of the centerline, hence\n", + "# they generate no data (XM_NODATA) interpolation values.\n", + "\n", + "# The points we are interpolating to\n", + "points = [\n", + " [5, 5, 0], [5, 0, 0], [5, -5, 0],\n", + " [20, 5, 0],\n", + " [20, 0, 0],\n", + " [20, -5, 0], [10, 20, 0], [30, -5, 0], [30, 30, 0],\n", + " [35, 20, 0], [45, 25, 0], [45, 15, 0],\n", + " [65, 20, 0], [-5, 0, 0]\n", + "]\n", + "\n", + "# Interpolate to the points\n", + "interper.interp_to_points(points)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### get_interpolation_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `get_interpolation_points()` method transforms and scales the points passed to the [`set_points()`](#InterpAnisotropic.set_points()) method into (s,n,z) space. The resulting points are then returned in a list. This method is not required for interpolation, but can be used for when you want to use the transformed/scaled data." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0. , 10. , 100. ],\n", + " [ 0. , -10. , 100. ],\n", + " [ 5. , 10. , 90. ],\n", + " [ 10. , 14.14213562, 90. ],\n", + " [ 5. , 5. , 60. ],\n", + " [ 5. , 0. , 50. ],\n", + " [ 5. , -5. , 70. ],\n", + " [ 5. , -10. , 90. ],\n", + " [ 10. , 20. , 80. ],\n", + " [ 17.07106781, 14.14213562, 80. ],\n", + " [ 17.07106781, 0. , 40. ],\n", + " [ 17.07106781, -14.14213562, 80. ],\n", + " [ 24.14213562, -20. , 80. ],\n", + " [ 24.14213562, 22.36067977, 70. ],\n", + " [ 24.14213562, 11.18033989, 50. ],\n", + " [ 24.14213562, 0. , 30. ],\n", + " [ 24.14213562, 0. , 30. ],\n", + " [ 22.37436867, -10.60660172, 70. ],\n", + " [ 26.64213562, -10. , 70. ],\n", + " [ 34.14213562, 10. , 50. ],\n", + " [ 34.14213562, -10. , 50. ]])" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interper.get_interpolation_points()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### get_transformed_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `get_transformed_points()` method transforms and scales a list of points. This method accepts the following two arguments:\n", + "\n", + "- `points` (iterable): The points to transform into (s,n,z) space.\n", + "- `get_closest` (bool): True to pick only the closest transformed point.\n", + "\n", + "The resulting points are returned in a list. The `get_transformed_points()` method allows us to use interpolation methods other then [inverse distance weighting](#Inverse-Distance-Weighted-Interpolation-(InterpIdw)) with our horizontally stretched data." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 2.5 , 5. , 0. ],\n", + " [ 2.5 , 0. , 0. ],\n", + " [ 2.5 , -5. , 0. ],\n", + " [ 10. , 5. , 0. ],\n", + " [ 11.76776695, 3.53553391, 0. ],\n", + " [ 10. , 0. , 0. ],\n", + " [ 10. , 0. , 0. ],\n", + " [ 10. , -5. , 0. ],\n", + " [ 5. , 20. , 0. ],\n", + " [ 13.53553391, 21.21320344, 0. ],\n", + " [ 11.76776695, -10.60660172, 0. ],\n", + " [ 24.14213562, 14.14213562, 0. ],\n", + " [ 22.37436867, 3.53553391, 0. ],\n", + " [ 26.64213562, 5. , 0. ],\n", + " [ 24.14213562, -7.07106781, 0. ],\n", + " [ 26.64213562, -5. , 0. ]])" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create the points that we will pass to get_transformed_points()\n", + "points = [\n", + " [5, 5, 0], [5, 0, 0], [5, -5, 0],\n", + " [20, 5, 0],\n", + " [20, 0, 0],\n", + " [20, -5, 0], [10, 20, 0], [30, -5, 0], [30, 30, 0],\n", + " [35, 20, 0], [45, 25, 0], [45, 15, 0],\n", + " [65, 20, 0], [-5, 0, 0]\n", + "]\n", + "\n", + "interper.get_transformed_points(points, False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Convenience Methods" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are a few methods available in xmsinterp that are designed to make it easier to use interpolation. The following section goes over how to use one of the convenience methods available in xmsinterp." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### interpolate_to_points() Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `interpolate_to_points()` method allows you to interpolate values from one set of points to another. The benefit of using this method is the ease of interpolating with different interpolation types from one function call. This benefit is shown in the following example, where `interpolate_to_points()` is used to interpolate with linear interpolation, inverse distance interpolation, and natural neighbor interpolation. `interpolate_to_points()` takes three required arguments, and three optional arguments. These arguments are listed below:\n", + "\n", + "- `interpolation_points` (Iterable): The points to be used for interpolation\n", + "- `points` (Iterable): The points to interpolate to\n", + "- `method` (string): The interpolation method to be used. One of: `'linear'`, `'idw'`, or `'natural_neighbor'`.\n", + "- `x` (string): The x dataset (optional). Ex: `'x'`\n", + "- `y` (string): The y dataset (optional). Ex: `'y'`\n", + "- `z` (string): The z dataset (optional). Ex: `'z'`" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "linear: (0.5, 2.5, 2.0, 1.600000023841858, 2.299999952316284, 2.0)\n", + "idw: (0.02681550197303295, 2.5, 1.5, 1.0, 2.829150915145874, 2.0)\n", + "natural neighbor: (0.5, 2.5, 2.0, 1.600000023841858, 2.299999952316284, 2.0)\n" + ] + } + ], + "source": [ + "# Import needed for interpolate_to_points()\n", + "from xms.interp.api.interpolator import interpolate_to_points\n", + "\n", + "# Create the points being interpolated from\n", + "points_from = ((0, 0, 0), (10, 0, 1), (10, 10, 2), (0, 10, 3))\n", + "\n", + "# Create the points being interpolated to\n", + "points_to = ((2, 1, 0), (5, 10, 2.5), (5, 5), (7, 3), (2, 7), (7, 7))\n", + "\n", + "# Call interpolate_to_points (linear)\n", + "print(f\"linear: {interpolate_to_points(method='linear', interpolation_points=points_from, points=points_to)}\")\n", + "\n", + "# Call interpolate_to_points (idw)\n", + "print(f\"idw: {interpolate_to_points(method='idw', interpolation_points=points_from, points=points_to)}\")\n", + "\n", + "# Call interpolate_to_points (natural neighbor)\n", + "print(f\"natural neighbor: {interpolate_to_points(method='natural_neighbor', interpolation_points=points_from, points=points_to)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example - 2D Grid Interpolation\n", + "\n", + "The xmsinterp library contains classes for performing 2d (x,y) linear, natural neighbor, and idw interpolation: InterpLinear and InterpIdw. Natural neighbor interpolation is performed using the linear interpolation class. 3d (x,y,z) interpolation can be performed using the idw class. Points (x,y) must be given to create the interpolation class.\n", + "\n", + "We will learn how to use the interpolation classes by using a set of 2D points (x,y) with a measurement at each point. These points come from a csv file. Then we will generate a grid that bounds these points and use different interpolation options to visualize the data." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from xms import interp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following code reads in data which we will interpolate from a csv file." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(-75, -16, 0.0), (-60, 32, 0.0), (-34, 50, 0.0), (-34, 27, 0.0), (-8, 40, 0.0), (16, 38, 0.0), (-25, 14, 43.64), (10, 18, 44.16), (27, 26, 0.0), (63, 35, 0.0), (-32, 0, 59.04), (-7, 7, 90.2), (26, 6, 67.2), (75, 7, 0.0), (-37, -15, 9.24), (-7, -13, 71.0), (2, -3, 98.4), (31, -15, 25.56), (60, -13, 0.0), (-50, -30, 0.0), (-30, -28, 0.0), (43, -22, 0.0), (-32, -50, 0.0), (27, -37, 0.0), (60, -33, 0.0)]\n" + ] + } + ], + "source": [ + "xs = []\n", + "ys = []\n", + "cs = []\n", + "\n", + "# Read in the data for our scatter plot\n", + "with open(\"plumedat.csv\") as input_file:\n", + " # Ignore column headers\n", + " input_file.readline()\n", + " \n", + " for line in input_file:\n", + " line = line.rstrip()\n", + " id,x,y,c = line.split(\",\")\n", + " xs.append(int(x))\n", + " ys.append(int(y))\n", + " cs.append(float(c))\n", + "\n", + "# Get input values as list of (x,y,z)\n", + "values = list(zip(xs,ys,cs))\n", + "print(values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below is an image that shows what our scatter plot data looks like when plotted with holoviews" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Scatter Plot Data](images/scatter_plot_1.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate grid for visualization\n", + "Get the min, max (x, y) of the data and generate a grid of points." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# get the (x,y) range of the data and expand by 10%\n", + "def buffer_range(range_min, range_max, buf_by=0.1):\n", + " buf = (range_max - range_min) * buf_by\n", + " return (range_min - buf, range_max + buf)\n", + "\n", + "# Get the min/max coordinates\n", + "x_min = min(xs)\n", + "x_max = max(xs)\n", + "y_min = min(ys)\n", + "y_max = max(ys)\n", + "\n", + "x_range = buffer_range(x_min, x_max)\n", + "y_range = buffer_range(y_min, y_max)\n", + "\n", + "# adjust these values for a higher/lower resolution grid\n", + "number_of_x_points=600\n", + "number_of_y_points=400\n", + "x = np.linspace(x_range[0], x_range[1], number_of_x_points)\n", + "y = np.linspace(y_range[0], y_range[1], number_of_y_points)\n", + "grid = np.meshgrid(x, y)\n", + "pts = np.stack([i.flatten() for i in grid], axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Interpolate to the grid using linear interpolation and display the results with matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "linear = interp.interpolate.InterpLinear(values)\n", + "z = linear.interpolate_to_points(pts)\n", + "# I would prefer to be able to set up an interpolator like this:\n", + "# linear = interp.Interpolator(kind='linear', values=df.values)\n", + "\n", + "# The commented out code below displays the interpolation with matplotlib resulting in the image below.\n", + "#zz = np.reshape(z, (len(y), len(x)))\n", + "#xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)\n", + "#xa.hvplot(x='x', y='y', height=500, cmap='viridis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Linear Interpolation](images/interpolation_1.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Interpolate using natural neighbor. The first example shows a \"constant\" nodal function and the second example shows a \"quadratic\" nodals function. A nodal function can better model trends that exist in the measured values." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "linear.set_use_natural_neighbor(on=True)\n", + "z = linear.interpolate_to_points(pts)\n", + "# z = linear.interpolate_to_points(pts, use='natural_neighbor')\n", + "\n", + "# The commented out code below displays the interpolation with matplotlib resulting in the image below.\n", + "#zz = np.reshape(z, (len(y), len(x)))\n", + "#xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)\n", + "#xa.hvplot(x='x', y='y', height=500, cmap='viridis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Linear Interpolation Using Natural Neighbor](images/interpolation_2.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now do natural neighbor with a quadratic nodal function." + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [], + "source": [ + "linear.set_use_natural_neighbor(on=True, nodal_function=\"quadratic\", \n", + " point_search_option=\"nearest_points\")\n", + "z = linear.interpolate_to_points(pts)\n", + "# z = linear.interp_to_pts(pts, use='natural_neighbor', nodal_func_type='quadratic', nd_func_pt_search_opt='nearest_pts')\n", + "\n", + "# The commented out code below displays the interpolation with matplotlib resulting in the image below.\n", + "#zz = np.reshape(z, (len(y), len(x)))\n", + "#xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)\n", + "#xa.hvplot(x='x', y='y', height=500, cmap='viridis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Linear Interpolation using natural neighbor and a quadratic nodal function](images/interpolation_3.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will use Inverse Distance Weighted (IDW) to interpolate to the grid. Notice that unlike Linear and Natural Neighbor interpolation, IDW interpolation can extrapolate beyond the bounds of the input data points." + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "idw = interp.interpolate.InterpIdw(values)\n", + "z = idw.interpolate_to_points(pts)\n", + "# idw = interp.Interpolator(kind='idw', values=df.values)\n", + "# z = idw.interpolate_to_points(pts)\n", + "\n", + "# The commented out code below displays the interpolation with matplotlib resulting in the image below.\n", + "#zz = np.reshape(z, (len(y), len(x)))\n", + "#xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)\n", + "#xa.hvplot(x='x', y='y', height=500, cmap='viridis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Inverse Distance Weighted Interpolation](images/interpolation_4.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now interpolate using a nodal function to try to better capture trends in the data set." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "idw.set_nodal_function(nodal_function=\"gradient_plane\")\n", + "z = idw.interpolate_to_points(pts)\n", + "# z = idw.interp_to_pts(pts, nodal_func_type='gradient_plane')\n", + "\n", + "# The commented out code below displays the interpolation with matplotlib resulting in the image below.\n", + "#zz = np.reshape(z, (len(y), len(x)))\n", + "#xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)\n", + "#xa.hvplot(x='x', y='y', height=500, cmap='viridis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Inverse Distance Weighted Interpolation with a Nodal Function](images/interpolation_5.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice, in the previous interpolation that we get negative values in some locations. If we assume that there should be no negatives values (like when measuring concentration) we can use the truncation options to adjust the interpolation." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "idw.set_truncation(maximum=150, minimum=0)\n", + "z = idw.interpolate_to_points(pts)\n", + "# z = idw.interpolate_to_points(pts, smax=150, smin=0)\n", + "\n", + "# The commented out code below displays the interpolation with matplotlib resulting in the image below.\n", + "#zz = np.reshape(z, (len(y), len(x)))\n", + "#xa = xr.DataArray(coords={'x': x, 'y': y}, dims=['x', 'y'], data=zz.T)\n", + "#xa.hvplot(x='x', y='y', height=500, cmap='viridis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Inverse Distance Weighted Interpolation with a Nodal Function and Truncation](images/interpolation_6.png)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/2D_Interpolation/images/interpolation_1.png b/examples/2D_Interpolation/images/interpolation_1.png new file mode 100644 index 000000000..5367279f1 Binary files /dev/null and b/examples/2D_Interpolation/images/interpolation_1.png differ diff --git a/examples/2D_Interpolation/images/interpolation_2.png b/examples/2D_Interpolation/images/interpolation_2.png new file mode 100644 index 000000000..dd992fcf8 Binary files /dev/null and b/examples/2D_Interpolation/images/interpolation_2.png differ diff --git a/examples/2D_Interpolation/images/interpolation_3.png b/examples/2D_Interpolation/images/interpolation_3.png new file mode 100644 index 000000000..5d4064456 Binary files /dev/null and b/examples/2D_Interpolation/images/interpolation_3.png differ diff --git a/examples/2D_Interpolation/images/interpolation_4.png b/examples/2D_Interpolation/images/interpolation_4.png new file mode 100644 index 000000000..4e3281e42 Binary files /dev/null and b/examples/2D_Interpolation/images/interpolation_4.png differ diff --git a/examples/2D_Interpolation/images/interpolation_5.png b/examples/2D_Interpolation/images/interpolation_5.png new file mode 100644 index 000000000..05c35a41d Binary files /dev/null and b/examples/2D_Interpolation/images/interpolation_5.png differ diff --git a/examples/2D_Interpolation/images/interpolation_6.png b/examples/2D_Interpolation/images/interpolation_6.png new file mode 100644 index 000000000..c348d90ba Binary files /dev/null and b/examples/2D_Interpolation/images/interpolation_6.png differ diff --git a/examples/2D_Interpolation/images/scatter_plot_1.png b/examples/2D_Interpolation/images/scatter_plot_1.png new file mode 100644 index 000000000..2f3943237 Binary files /dev/null and b/examples/2D_Interpolation/images/scatter_plot_1.png differ diff --git a/examples/2D_Interpolation/plumedat.csv b/examples/2D_Interpolation/plumedat.csv new file mode 100644 index 000000000..4add45dea --- /dev/null +++ b/examples/2D_Interpolation/plumedat.csv @@ -0,0 +1,26 @@ +id,x,y,c +1,-75,-16,0 +2,-60,32,0 +3,-34,50,0 +4,-34,27,0 +5,-8,40,0 +6,16,38,0 +7,-25,14,43.64 +8,10,18,44.16 +9,27,26,0 +10,63,35,0 +11,-32,0,59.04 +12,-7,7,90.2 +13,26,6,67.2 +14,75,7,0 +15,-37,-15,9.24 +16,-7,-13,71 +17,2,-3,98.4 +18,31,-15,25.56 +19,60,-13,0 +20,-50,-30,0 +21,-30,-28,0 +22,43,-22,0 +23,-32,-50,0 +24,27,-37,0 +25,60,-33,0 diff --git a/examples/xms.yml b/examples/xms.yml deleted file mode 100644 index ae269bd2b..000000000 --- a/examples/xms.yml +++ /dev/null @@ -1,23 +0,0 @@ -#xms.yml -# Configuration file for creating a Conda environment with dependencies needed for the xms libraries. -# Create the environment by running the following command (after installing Miniconda): -# $ conda env create -f xms.yml - -name: xms - -channels: - - Aquaveo - - pyviz/label/dev - - defaults - - conda-forge - -dependencies: - - python=3.10.* - - xmscore - - xmsinterp - - xmsgrid - - xmsmesh - - xmsextractor - - xmsstamper - - xmsgridtrace - - pyviz