Skip to content

Commit

Permalink
Add new filter sample_over_line and refactor plot_over_line (pyvista#525
Browse files Browse the repository at this point in the history
)

* Refactor plot over line to enable retrieving result

* Return line object instead

* Move positive resolution check to Line, remove integer check.  Add more testing.

* Remove extra blank line

* add missing blank line
  • Loading branch information
MatthewFlamm authored and banesullivan committed Jan 13, 2020
1 parent f668c2e commit 6d017f2
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 12 deletions.
44 changes: 34 additions & 10 deletions pyvista/core/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1599,12 +1599,41 @@ def decimate_boundary(dataset, target_reduction=0.5):
return dataset.extract_geometry().triangulate().decimate(target_reduction)


def sample_over_line(dataset, pointa, pointb, resolution=None):
"""Sample a dataset onto a line.
Parameters
----------
pointa : np.ndarray or list
Location in [x, y, z].
pointb : np.ndarray or list
Location in [x, y, z].
resolution : int
Number of pieces to divide line into. Defaults to number of cells
in the input mesh. Must be a positive integer.
Return
------
sampled_line : pv.PolyData
Line object with sampled data from dataset.
"""
if resolution is None:
resolution = int(dataset.n_cells)
# Make a line and sample the dataset
line = pyvista.Line(pointa, pointb, resolution=resolution)

sampled_line = line.sample(dataset)
return sampled_line


def plot_over_line(dataset, pointa, pointb, resolution=None, scalars=None,
title=None, ylabel=None, figsize=None, figure=True,
show=True):
"""Sample a dataset along a high resolution line.
"""Sample a dataset along a high resolution line and plot.
Also plot the variables of interest in 2D where the X-axis is distance from
Plot the variables of interest in 2D where the X-axis is distance from
Point A and the Y-axis is the variable of interest. Note that this filter
returns None.
Expand Down Expand Up @@ -1646,21 +1675,16 @@ def plot_over_line(dataset, pointa, pointb, resolution=None, scalars=None,
except ImportError:
raise ImportError('matplotlib must be available to use this filter.')

if resolution is None:
resolution = int(dataset.n_cells)
if not isinstance(resolution, int) or resolution < 0:
raise RuntimeError('`resolution` must be a positive integer, not {}'.format(type(resolution)))
# Make a line and probe the dataset
line = pyvista.Line(pointa, pointb, resolution=resolution)
sampled = line.sample(dataset)
# Sample on line
sampled = DataSetFilters.sample_over_line(dataset, pointa, pointb, resolution)

# Get variable of interest
if scalars is None:
field, scalars = dataset.active_scalars_info
values = sampled.get_array(scalars)
distance = sampled['Distance']

# Remainder of the is plotting
# Remainder is plotting
if figure:
plt.figure(figsize=figsize)
# Plot it in 2D
Expand Down
2 changes: 2 additions & 0 deletions pyvista/utilities/geometric_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ def Line(pointa=(-0.5, 0., 0.), pointb=(0.5, 0., 0.), resolution=1):
number of pieces to divide line into
"""
if resolution <= 0:
raise ValueError('Resolution must be positive')
if np.array(pointa).size != 3:
raise TypeError('Point A must be a length three tuple of floats.')
if np.array(pointb).size != 3:
Expand Down
21 changes: 21 additions & 0 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,27 @@ def test_streamlines():
assert src.n_points == 25


def test_sample_over_line():
"""Test that we get a sampled line."""
name = 'values'

line = pyvista.Line([0, 0, 0], [0, 0, 10], 9)
line[name] = np.linspace(0, 10, 10)

sampled_line = line.sample_over_line([0, 0, 0.5], [0, 0, 1.5], 2)

expected_result = np.array([0.5, 1, 1.5])
assert np.allclose(sampled_line[name], expected_result)
assert name in line.array_names # is name in sampled result

# test no resolution
sphere = pyvista.Sphere(center=(4.5,4.5,4.5), radius=4.5)
sampled_from_sphere = sphere.sample_over_line([3, 1, 1], [-3, -1, -1])
assert sampled_from_sphere.n_points == sphere.n_cells + 1
# is sampled result a polydata object
assert isinstance(sampled_from_sphere, pyvista.PolyData)


def test_plot_over_line():
"""this requires matplotlib"""
mesh = examples.load_uniform()
Expand Down
14 changes: 12 additions & 2 deletions tests/test_geometric_objects.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import pytest

import pyvista

Expand Down Expand Up @@ -33,13 +34,22 @@ def test_plane():


def test_line():
line = pyvista.Line((0,0,0), (10, 1., 3))
pointa = (0, 0, 0)
pointb = (10, 1., 3)

line = pyvista.Line(pointa, pointb)
assert line.n_points == 2
assert line.n_cells == 1
line = pyvista.Line((0,0,0), (10, 1., 3), 10)
line = pyvista.Line(pointa, pointb, 10)
assert line.n_points == 11
assert line.n_cells == 1

with pytest.raises(ValueError):
pyvista.Line(pointa, pointb, -1)

with pytest.raises(TypeError):
pyvista.Line(pointa, pointb, 0.1) # from vtk


def test_cube():
cube = pyvista.Cube()
Expand Down

0 comments on commit 6d017f2

Please sign in to comment.