Source code for homcloud.paraview_interface

"""
*This module is now deprecated. Please use pyvista instead.*


This module provides the paraview interface from homcloud.interface module.

The basic model of this module is "pipeline" model. A data object is
filtered by the chain of pipeline nodes, and the result is shown.
The objects of :class:`PipelineNode` correspond the node of the pipeline,
and you can adjust visualization by these objects.

You can use many methods of :class:`PipelineNode` to adjust the visualization,
and you can construct a new pipeline node by the following methods:

* :meth:`PipelineNode.threshold`
* :meth:`PipelineNode.clip_sphere`

Todo:

* Add clip_box method

"""

import numbers
import sys
from tempfile import NamedTemporaryFile, TemporaryDirectory
import os
import itertools
import math
import warnings

import numpy as np

import homcloud.utils as utils
import homcloud.pict.pict3d_vtk as pict3d_vtk
from homcloud.delegate import forwardable


class ParaViewColors(object):
    def __init__(self, n_colors):
        self.n_colors = n_colors
        self.color_scalars = np.linspace(0, 1.0, n_colors + 3)

    @property
    def various_colors(self):
        return self.color_scalars[:-3]

    def birth_color(self):
        return self.color_scalars[-2]

    def death_color(self):
        return self.color_scalars[-1]

    def output_lookup_table(self, f):
        f.write("LOOKUP_TABLE color_table {}\n".format(self.n_colors + 3))
        for x in np.linspace(0.0, 1.0, self.n_colors + 1):
            self.output_various_colors(f, x)
        self.output_birthdeath_colors(f)

    def output_various_colors(self, f, relative_value):
        f.write("{} {} {} 1.0\n".format(*self.color_spec(relative_value)))

    @staticmethod
    def color_spec(x):
        y, k = math.modf(x * 6)
        if k == 0 or k == 6:
            return (1, y, 0)
        if k == 1:
            return (1 - y, 1, 0)
        if k == 2:
            return (0, 1, y)
        if k == 3:
            return (0, 1 - y, 1)
        if k == 4:
            return (y, 0, 1)
        if k == 5:
            return (1, 0, 1 - y)
        return (0.5, 0.5, 0.5)

    @staticmethod
    def output_birthdeath_colors(f):
        f.write("0.8 0.8 0.8 1.0\n")
        f.write("1.0 1.0 1.0 1.0\n")


# TODO: this class requires unit tests
[docs] @forwardable class BaseDrawer(object): """ This class represents the generator of a VTK file. Args: n_colors (int): The number of colors column_spec (dict[str, float or None]): The pairs of the names of the columns and default values. """ def __init__(self, n_colors, column_spec): self.pvcolors = ParaViewColors(n_colors) self.lines = [] self.colors = [] self.columns = {name: list() for name in column_spec} self.default_values = { name: default_val for (name, default_val) in column_spec.items() if default_val is not None } self.vertices = [] __delegator_definitions__ = {"pvcolors": ["various_colors", "birth_color", "death_color"]} def draw_line(self, p, q, color, **threshold_values): self.lines.append((p, q)) self.append_attributes(color, threshold_values) def append_attributes(self, color, threshold_values): self.colors.append(color) for key in self.columns: self.columns[key].append(self.get_threshold_value(threshold_values, key)) def get_threshold_value(self, values, key): if key in values: return values[key] else: return self.default_values[key] def invoke(self, wait=True): with TemporaryDirectory() as tmpdir: path = os.path.join(tmpdir, "tmp.vtk") self.output(path) utils.invoke_paraview(path, wait=wait) def output(self, path): with open(path, "w") as f: self.write(f) def write(self, f): self.output_header(f) self.output_polygon_data(f) self.output_line_colors(f) self.pvcolors.output_lookup_table(f) self.output_columns(f) @staticmethod def output_header(f): f.write("# vtk DataFile Version 2.0\n") f.write("volume optimal cycles\n") f.write("ASCII\n") def output_polygon_data(self, f): f.write("DATASET POLYDATA\n") self.output_points(f) self.output_vertices(f) self.output_lines(f) self.output_polygons(f) def output_vertices(self, f): if not self.vertices: return f.write("VERTICES {} {}\n".format(self.num_vertices(), self.num_vertices() * 2)) for v in self.vertices: f.write("1 {}\n".format(v)) f.write("\n") def output_lines(self, f): pass def output_polygons(self, f): pass def output_line_colors(self, f): f.write("CELL_DATA {}\n".format(len(self.colors))) f.write("SCALARS colors float 1\n") f.write("LOOKUP_TABLE color_table\n") for n in self.colors: f.write("{}\n".format(n)) def output_columns(self, f): for key, values in self.columns.items(): f.write("SCALARS {} float 1\n".format(key)) f.write("LOOKUP_TABLE default\n") for value in values: f.write("{}\n".format(value)) def num_lines(self): return len(self.lines) def num_vertices(self): return len(self.vertices) @staticmethod def reformat_point(point): if len(point) == 3: return point if len(point) == 2: return (point[0], point[1], 0)
class BaseCellDrawer: def draw_cells(self, geom_resolver, cells, color, **values): for cell in cells: self.draw_cell(geom_resolver, cell, color, **values) def draw_boundary_cells(self, geom_resolver, cells, color, **values): self.draw_cells(geom_resolver, geom_resolver.boundary_cells(cells), color, **values)
[docs] class SimplexDrawer(BaseDrawer, BaseCellDrawer): def __init__(self, n_colors, points, column_names): super().__init__(n_colors, column_names) self.points = [self.reformat_point(p) for p in points] def draw_cell(self, geom_resolver, cell_index, color, **threshold_values): self.draw_simplex(geom_resolver.index_to_simplex[cell_index], color, **threshold_values) def draw_simplex(self, simplex, color, **threshold_values): for edge in itertools.combinations(simplex, 2): self.draw_line(edge[0], edge[1], color, **threshold_values) def draw_vertex(self, vertex, color, **threshold_values): self.vertices.append(vertex) self.append_attributes(color, threshold_values) def draw_all_vertices(self, color, **threshold_values): for i in range(len(self.points)): self.draw_vertex(i, color, **threshold_values) def output_points(self, f): f.write("POINTS {} double\n".format(self.num_points())) for point in self.points: f.write("{} {} {}\n".format(point[0], point[1], point[2])) f.write("\n") def output_lines(self, f): f.write("LINES {} {}\n".format(self.num_lines(), self.num_lines() * 3)) for line in self.lines: f.write("2 {} {}\n".format(line[0], line[1])) f.write("\n") def num_points(self): return len(self.points)
[docs] class CubeDrawer(BaseDrawer, BaseCellDrawer): def __init__(self, n_colors, dims, column_names): super().__init__(n_colors, column_names) self.dims = dims assert len(dims) in [2, 3] @staticmethod def dvs(non_deg): n = len(non_deg) dvs = [] def iter(k, dv): if k == n: dvs.append(dv.copy()) else: if non_deg[k]: for b in [0, 1]: dv[k] = b iter(k + 1, dv) else: iter(k + 1, dv) iter(0, np.zeros(n, dtype=int)) return dvs @staticmethod def dls(non_deg): n = len(non_deg) dls = [] for k in range(n): if non_deg[k]: dl = np.zeros(n, dtype=int) dl[k] = 1 dls.append(dl) return dls def draw_cell(self, geom_resolver, cell_index, color, **threshold_values): coords, nondeg = geom_resolver.decode_index(cell_index) self.draw_cube(coords, nondeg, color, **threshold_values) def draw_cube(self, coord, non_deg, color, **threshold_values): for dv in self.dvs(non_deg): for dl in self.dls(non_deg): if np.max(dv + dl) < 2: self.draw_line(coord + dv, coord + dv + dl, color, **threshold_values) def ndim(self): return len(self.dims) def coord2index(self, coord): index = 0 for k in range(self.ndim()): index = index * self.dims[k] + coord[k] return index def index2coord(self, index): coord = [0] * self.ndim() for k in reversed(range(self.ndim())): index, coord[k] = divmod(index, self.dims[k]) return coord def output_points(self, f): f.write("POINTS {} double\n".format(self.num_points())) for k in range(self.num_points()): coord = self.index2coord(k) f.write("{} {} {}\n".format(*self.reformat_point(coord))) f.write("\n") def num_points(self): return int(np.prod(self.dims)) def output_lines(self, f): f.write("LINES {} {}\n".format(self.num_lines(), self.num_lines() * 3)) for line in self.lines: f.write("2 {} {}\n".format(self.coord2index(line[0]), self.coord2index(line[1]))) f.write("\n")
[docs] class SparseCubeDrawer(BaseDrawer): def __init__(self, n_colors, ndim, column_names): super().__init__(n_colors, column_names) self.ndim = ndim self.points = [] assert ndim in [2, 3] def draw_cube(self, coord, non_deg, color, **threshold_values): indices, dvs = self.prepare_points(coord, non_deg) for dv in dvs: for dl in CubeDrawer.dls(non_deg): if np.max(dv + dl) < 2: self.draw_line(indices[tuple(dv)], indices[tuple(dv + dl)], color, **threshold_values) def prepare_points(self, coord, non_deg): dvs = CubeDrawer.dvs(non_deg) indices = np.zeros([2] * self.ndim, dtype=int) for dv in dvs: indices[tuple(dv)] = len(self.points) self.points.append(np.flip(dv + coord)) return indices, dvs def output_points(self, f): f.write("POINTS {} double\n".format(self.num_points())) for point in self.points: f.write("{} {} {}\n".format(point[0], point[1], point[2])) f.write("\n") def num_points(self): return len(self.points) def output_lines(self, f): f.write("LINES {} {}\n".format(self.num_lines(), self.num_lines() * 3)) for line in self.lines: f.write("2 {} {}\n".format(line[0], line[1])) f.write("\n")
[docs] class SparseBitmapDrawer(BaseDrawer): def __init__(self, n_colors, column_names): super().__init__(n_colors, column_names) self.vertices = [] self.n_voxels = 0 def draw_voxel(self, coord, color, **threshold_values): self.n_voxels += 1 for d1 in (-0.4, 0.4): for d2 in (-0.4, 0.4): for d3 in (-0.4, 0.4): r = (coord[0] + d1, coord[1] + d2, coord[2] + d3) self.vertices.append(r) self.append_attributes(color, threshold_values) def output(self, path): with open(path, "w") as f: self.output_header(f) self.output_voxel_data(f) self.output_line_colors(f) self.pvcolors.output_lookup_table(f) self.output_columns(f) def output_voxel_data(self, f): f.write("DATASET UNSTRUCTURED_GRID\n") f.write("POINTS {} double\n".format(len(self.vertices))) for r in self.vertices: f.write(" ".join(map(str, r))) f.write("\n") f.write("CELLS {} {}\n".format(self.n_voxels, 9 * self.n_voxels)) for n in range(self.n_voxels): f.write("8 {}\n".format(" ".join(map(str, range(n * 8, (n + 1) * 8))))) f.write("CELL_TYPES {}\n".format(self.n_voxels)) for _ in range(self.n_voxels): f.write("11\n")
[docs] class LinesDrawer(BaseDrawer): def __init__(self, n_colors, column_names): super().__init__(n_colors, column_names) self.points = [] self.point2index = dict() self.lines = [] def index_of(self, p): if p in self.point2index: return self.point2index[p] else: index = len(self.points) self.point2index[p] = index self.points.append(p) return index def draw_line(self, p1, p2, color, **threshold_values): index1 = self.index_of(p1) index2 = self.index_of(p2) self.lines.append((index1, index2)) self.append_attributes(color, threshold_values) def output_points(self, f): f.write("POINTS {} double\n".format(self.num_points())) for point in self.points: point = self.reformat_point(point) f.write("{} {} {}\n".format(point[0], point[1], point[2])) f.write("\n") def num_points(self): return len(self.points) def output_lines(self, f): f.write("LINES {} {}\n".format(self.num_lines(), self.num_lines() * 3)) for line in self.lines: f.write("2 {} {}\n".format(line[0], line[1])) f.write("\n") def draw_loop(self, path, color, **threshold_values): for k in range(len(path) - 1): self.draw_line(path[k], path[k + 1], color, **threshold_values)
[docs] class PolyLineDrawer(BaseDrawer): def __init__(self, n_colors, points, column_names): super().__init__(n_colors, column_names) self.points = [self.reformat_point(p) for p in points] self.append_attributes(0, {}) def output_points(self, f): f.write("POINTS {} double\n".format(self.num_points())) for point in self.points: f.write("{} {} {}\n".format(point[0], point[1], point[2])) f.write("\n") def output_lines(self, f): f.write("LINES 1 {}\n".format(self.num_points() + 1)) f.write("{} ".format(self.num_points())) for k in range(self.num_points()): f.write(" {}".format(k)) f.write("\n\n") def num_points(self): return len(self.points)
[docs] class SurfaceDrawer(BaseDrawer): def __init__(self, n_colors, surface, column_names): super().__init__(n_colors, column_names) self.num_triagnles = len(surface) self.surface = surface for _ in range(self.num_triagnles): self.append_attributes(0, {}) def output_points(self, f): points = np.array(self.surface).reshape(3 * self.num_triagnles, 3) f.write("POINTS {} double\n".format(self.num_triagnles * 3)) for point in points: f.write("{} {} {}\n".format(point[0], point[1], point[2])) f.write("\n") def output_polygons(self, f): f.write("POLYGONS {} {}\n".format(self.num_triagnles, self.num_triagnles * 4)) for k in range(self.num_triagnles): f.write("3 {} {} {}\n".format(3 * k, 3 * k + 1, 3 * k + 2))
@forwardable class TempFile(object): def __init__(self, suffix): self.named_tempfile = NamedTemporaryFile("w+", suffix=suffix, delete=False) self.cleanup_done = False __delegator_definitions__ = {"named_tempfile": ["name", "close", "write"]} def cleanup(self): self.close() if not self.cleanup_done: os.unlink(self.name) self.cleanup_done = True def __del__(self): self.cleanup() # NOTE: __enter__ and __exit__ are not implemented since # in this module with statement is used to the class
[docs] class PipelineNode(object): """This class represents elements in a pipeline in ParaView. This class is the base class for paraview interface classes. You should not create an instance of this class directly. """ def __init__(self, parent=None): self.index = new_index() self.parent = parent self._representation = None self.opacity = None self.color = None self.color_field = None self.colorbar_range = None self.pointsize = None self.linewidth = None def variable(self): return "s" + str(self.index)
[docs] def to_paraview_node(self): """Returns self.""" return self
def representation(self): if self._representation: return self._representation if self.parent is None: return False return self.parent.representation() def write_code(self, out, already_written, isleaf): if self.variable() in already_written: return already_written.add(self.variable()) if self.parent: self.parent.write_code(out, already_written, False) self.write_constructor(out) if isleaf: out.write("Show({})\n".format(self.variable())) self.write_specialized_code(out, already_written) if isleaf: self.write_displayproperty_code(out, already_written) def write_displayproperty_code(self, out, already_written): out.write("dp = GetDisplayProperties({})\n".format(self.variable())) if self.representation(): out.write("dp.Representation = '{}'\n".format(self.representation())) if self.opacity is not None: out.write("dp.Opacity = {}\n".format(self.opacity)) if self.pointsize is not None: out.write("dp.PointSize = {}\n".format(self.pointsize)) if self.color_field is not None: self.write_color_filed(out) if self.color is not None: out.write("dp.AmbientColor = ({}, {}, {})\n".format(*self.color)) out.write("dp.DiffuseColor = ({}, {}, {})\n".format(*self.color)) out.write("dp.ColorArrayName = [dp.ColorArrayName[0], r'']\n") if self.linewidth is not None: out.write("dp.LineWidth = {}\n".format(self.linewidth)) def write_color_filed(self, out): if self.colorbar_range is None: out.write( "dp.LookupTable = MakeBlueToRedLT(*{}." "{}[r'{}'].GetRange())\n".format(self.variable(), self.data_attr_name(), self.color_field) ) else: out.write("dp.LookupTable = MakeBlueToRedLT({}, {})\n".format(*self.colorbar_range)) out.write("dp.ColorArrayName = [r'{}', r'{}']\n".format(self.color_array_type(), self.color_field)) def write_specialized_code(self, out, already_written): pass
[docs] def threshold(self, field, range): """ Create a new pipeline node for thresholding whose parent is `self`. Only the elements whose `field` are in the `range` when the returned object is passed to :meth:`show`. Args: field (string): The name of the field which have the thresholded value. range (tuple[float, float] or float): The upper and lower bounds of the values. If an float number is given, the threshold is (range, range). Returns: Threshold: A new PipelineNode object for thresholding. """ if isinstance(range, numbers.Number): range = (range, range) return Threshold(self, field, range)
[docs] def clip_sphere(self, center, radius, inside_out=True): """ Create a new pipeline node to clip the object with a sphere shape. Args: center (tuple[float, float, float]): The center of the clipping sphere radius (float): The radius of the clipping sphere inside_out (bool): If True, only the elements *in* the shpere are shown. If False, only the elements *outside* of the sphere is shown. Returns: SphereClip: A new PipelineNode object for sphere clipping. """ return SphereClip(self, center, radius, inside_out)
[docs] def color_by(self, field, range=None): """ Set the coloring by field name. Args: field (string or int): The name of the field. range (tuple[float, float] or None): The upper and lower bounds of the colorbar. If None, the minimal and maximal values of the field are used. Returns: self """ if isinstance(field, int): field = "Field {}".format(field) self.color_field = field self.colorbar_range = range return self
def data_attr_name(self): return self.parent.data_attr_name() def color_array_type(self): return self.parent.color_array_type()
[docs] def set_opacity(self, opacity): """ Set the opacity. * 0.0 - completely transparent * 1.0 - completely opaque Args: opacity (float): The opacity. Returns: self """ self.opacity = opacity return self
[docs] def set_color(self, color): """ Set the color. Args: color (tuple[float, float, float]): The RGB values (0.0 to 1.0) Returns: self """ self.color = color return self
[docs] def set_pointsize(self, size): """ Set the pointsize. Args: pointsize (float): The size of the points Returns: self """ self.pointsize = size return self
def set_representation(self, rep): if rep not in ["Wireframe", "Points", "Surface", "Surface With Edges"]: raise ValueError("Representation {} is not acceptable".format(rep)) self._representation = rep return self
[docs] def set_linewidth(self, width): """ Set the linewidth. Args: width (float): The width of the lines Returns: self """ self.linewidth = width return self
def debug_print(self): write_python_code(sys.stdout, [self]) return self def cleanup(self): if self.parent: self.parent.cleanup()
[docs] class VTK(PipelineNode): """ This class represents a VTK data source in paraview. """ def __init__(self, path, gui_name=None, file=None): super().__init__() self.path = path self.gui_name = gui_name if gui_name is not None else path self.file = file def cleanup(self): if self.file: self.file.cleanup() def write_constructor(self, out): out.write( "{} = LegacyVTKReader(FileNames=r'{}'," " guiName=r'{}')\n".format(self.variable(), self.path, self.gui_name) ) def data_attr_name(self): return "CellData" def color_array_type(self): return "CELLS"
[docs] class XMLVTI(PipelineNode): """ This class represents a VTI data source in XML format in paraview. """ def __init__(self, path, gui_name, file=None): super().__init__() self.path = path self.gui_name = gui_name if gui_name is not None else path self.file = file self._representation = "Surface" self.color_field = "value" def cleanup(self): if self.file: self.file.cleanup() def write_constructor(self, out): out.write( "{} = XMLImageDataReader(FileName=r'{}', " "guiName=r'{}')\n".format(self.variable(), self.path, self.gui_name) ) def data_attr_name(self): return "CellData" def color_array_type(self): return "CELLS"
[docs] def VoxelData(array, gui_name=None, offsets=[0, 0, 0]): """ Returns :class:`PipelineNode` object representing a voxel data. Args: array (numpy.ndarray): An array. gui_name (string or None): The name shown in Pipeline Browser in paraview's GUI. Returns: VTK: A pipeline node object """ f = TempFile(".vti") pict3d_vtk.write_vti_xmlfile(f, array, offsets) f.close() return XMLVTI(f.name, gui_name, f)
[docs] def PolyLine(array, gui_name=None): """ Returns :class:`PipelineNode` object representing a polyline. Args: array (numpy.ndarray): An array of points. gui_name (string or None): The name shown in Pipeline Browser in paraview's GUI. Returns: VTK: A pipeline node object """ f = TempFile(".vtk") drawer = PolyLineDrawer(2, array, {}) drawer.write(f) f.close() return VTK(f.name, gui_name, f).set_representation("Wireframe")
def Lines(lines, gui_name=None): f = TempFile(".vtk") drawer = LinesDrawer(1, {}) for line in lines: drawer.draw_line(tuple(line[0]), tuple(line[1]), 0) drawer.write(f) f.close() return VTK(f.name, gui_name, f).set_representation("Wireframe") def Surface(surface, gui_name=None): f = TempFile(".vtk") drawer = SurfaceDrawer(2, surface, {}) drawer.write(f) f.close() return VTK(f.name, gui_name, f).set_representation("Surface")
[docs] class PointCloud(PipelineNode): """ This class represents a pointcloud data source in paraview. Args: path (string): The filepath of the pointcloud. dim (int): The dimension of the space in which the pointcloud lives. delimiter (string): The delimiter of elements in a pointcloud file. If you want to show a CSV file, please specify ",". gui_name (string or None): The name shown in Pipeline Browser in paraview's GUI. Notes: This is constructed by CSVReader and TableToPoints. """ def __init__(self, path, dim=3, delimiters=" ", gui_name=None, file=None): super().__init__() self.path = path self.dim = dim self.delimiters = delimiters self.gui_name = gui_name or self.path self.file = file assert dim in [2, 3] def cleanup(self): if self.file: self.file.cleanup()
[docs] @staticmethod def from_array(array, dim=3, gui_name=None): """ Construct a pipeline node for pointcloud from an ndarray object. Args: array (nupmy.ndarray): The pointcloud data. dim (int): The dimension of the space in which the pointcloud lives. gui_name (string): The name shown in Pipeline Browser in paraview's GUI. Returns: PointCloud: A pipeline node object. """ f = TempFile(".txt") np.savetxt(f, array) f.close() return PointCloud(f.name, dim, " ", gui_name, f)
def representation(self): return "Points" def write_constructor(self, out): def quote(s): return s.translate( { "\t": "\\t", "\n": "\\n", } ) out.write( "s = CSVReader(FileName=r'{}', FieldDelimiterCharacters='{}'," " guiName=r'{}', HaveHeaders=0)\n".format(self.path, quote(self.delimiters), self.gui_name) ) out.write(self.table_to_points_template().format(self.variable())) def table_to_points_template(self): if self.dim == 3: return "{} = TableToPoints(s, XColumn='Field 0', YColumn='Field 1', ZColumn='Field 2')\n" elif self.dim == 2: return "{} = TableToPoints(s, XColumn='Field 0', YColumn='Field 1', ZColumn='Field 0', a2DPoints=1)\n" def data_attr_name(self): return "PointData" def color_array_type(self): return "POINTS"
[docs] class Threshold(PipelineNode): """ This class represents a pipeline node for thresholding. You should construct the instance of this class by :meth:`PipelineNode.threshold`. """ def __init__(self, parent, field, range): super().__init__(parent) self.field = field self.range = range def write_constructor(self, out): out.write("{} = Threshold({})\n".format(self.variable(), self.parent.variable())) def write_specialized_code(self, out, already_written): out.write("{}.Scalars = ['CELLS', r'{}']\n".format(self.variable(), self.field)) out.write("{}.ThresholdRange = ({}, {})\n".format(self.variable(), self.range[0], self.range[1]))
[docs] class SphereClip(PipelineNode): """ This class represents a pipeline node for sphere clipping. You should construct the instance of this class by :meth:`PipelineNode.clip_sphere`. """ def __init__(self, parent, center, radius, inside_out=True): super().__init__(parent) self.center = center self.radius = radius self.inside_out = inside_out def write_constructor(self, out): out.write( "{} = Clip({}, InsideOut={}, ClipType='Sphere')\n".format( self.variable(), self.parent.variable(), int(self.inside_out), ) ) def write_specialized_code(self, out, already_written): out.write("{}.ClipType.Center = [{}, {}, {}]\n".format(self.variable(), *self.center)) out.write("{}.ClipType.Radius = {}\n".format(self.variable(), self.radius))
[docs] def write_python_code(out, sources, bgcolor): """ Write a python code generated by `sources` to `out`. Args: out (io-like): The output IO object. sources (list of PipelineNode): Pipeline nodes to be output. """ already_written = set() out.write("from paraview.simple import *\n") for source in sources: source.write_code(out, already_written, True) out.write("view = GetActiveView()\n") if bgcolor: out.write("view.Background = [{}, {}, {}]\n".format(*bgcolor)) out.write("Render()\n")
[docs] def show(sources, path=None, wait=True, bgcolor=None): """ Shows `sources` by invoking paraview. Args: sources (list of PipelineNode): Pipeline nodes to be output. path (string or None): The output filename. If this parameter is None, a temporary filepath is generated and use it. If `path` is not None, the file remains after stopping paraview. wait (bool): If True, this function returns after paraview stops. If False, this function returns immediately after paraview is invoked by using backgroup process mechanism. bgcolor (None or tuple[float, float, float]): Background color. """ warnings.warn( "HomCloud's Paraview interface is now deprecated. " "The feature is planned to removed in the future." ) f = open(path, "w") if path else TempFile(".py") nodes = [s.to_paraview_node() for s in sources] write_python_code(f, nodes, bgcolor) f.close() # sp.run(["cmd.exe", "/k", "type", path]) def finalize(): if isinstance(f, TempFile): f.cleanup() for node in nodes: node.cleanup() utils.invoke_paraview("--script={}".format(f.name), wait=wait, finalize=finalize)
current_index = 0 def new_index(): global current_index current_index += 1 return current_index