{"action":"created","comment":{"url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments/32971519","id":32971519,"diff_hunk":"@@ -0,0 +1,871 @@\n+:author: Cory Quammen\n+:email: cory.quammen@kitware.com\n+:institution: Kitware, Inc.\n+\n+-------------------------------------------------------------------------\n+Scientific Data Analysis and Visualization with Python, VTK, and ParaView\n+-------------------------------------------------------------------------\n+\n+.. class:: abstract\n+\n+   VTK and ParaView are leading software packages for data analysis\n+   and visualization. Since their early years, Python has played an\n+   important role in each package. In many use cases, VTK and ParaView\n+   serve as modules used by Python applications. In other use cases,\n+   Python modules are used to generate visualization components within\n+   VTK. In this paper, we provide an overview of Python integration in\n+   VTK and ParaView and give some concrete examples of usage. We also\n+   provide a roadmap for additional Python integration in VTK and\n+   ParaView in the future.\n+\n+.. class:: keywords\n+\n+   visualization, VTK, ParaView\n+\n+Introduction\n+------------\n+\n+The Visualization Toolkit (VTK) is an open-source, freely available\n+software system for 3D computer graphics and visualization. It\n+consists of a set of C++ class libraries and bindings for Python along\n+with several other languages. VTK supports a wide variety of\n+visualization algorithms for 2D and 3D scalar, vector, tensor,\n+texture, and volumetric data, as well as advanced modeling techniques\n+such as implicit modeling, polygon reduction, mesh smoothing, cutting,\n+contouring, and Delaunay triangulation. VTK has an extensive\n+information visualization framework and a suite of 3D interaction\n+widgets. The toolkit supports parallel processing and integrates with\n+various GUI toolkits such as Qt and Tk. Python bindings expose nearly\n+all VTK classes and class methods, making it possible to write full\n+VTK-based applications in Python. VTK also includes interfaces to\n+popular Python modules such as NumPy and matplotlib. Support for\n+writing custom VTK algorithms in Python is also available.\n+\n+Based on VTK, ParaView is a scalable visualization tool that runs on a\n+variety of platforms ranging from PCs to some of the largest\n+supercomputers in the world. ParaView consists of a suite of\n+executables for generating data visualizations using the techniques\n+available in VTK. ParaView executables interface with Python in a\n+number of ways: data sources, filters, and integrated plots can be\n+defined via Python code, data can be queried with Python expressions,\n+and several executables can be controlled interactively with Python\n+commands in an integrated Python shell. Batch processing via Python\n+scripts that are either written by hand or generated as a trace of\n+events during an interactive visualization session is available for\n+offline visualization generation.\n+\n+This paper is organized into two main sections. In the first section,\n+I describe the relationship between VTK and Python and describe some\n+interfaces between the two. In the second section, I detail the\n+relationship between ParaView and Python. Examples of Python usage in\n+both packages are provided throughout. I also provide a roadmap for\n+additional Python support in VTK and ParaView.\n+\n+Python and VTK\n+--------------\n+\n+Since 1997, VTK has provided language bindings for Python. Over the\n+years, Python has become increasingly important to VTK, both as a\n+route to using VTK, as well as to the development of VTK itself.\n+\n+Python Language Bindings for VTK\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+The Python binding support in VTK has evolved so that today nearly\n+every semantic feature of C++ used by VTK has a direct semantic analog\n+in Python. C++ classes from VTK are wrapped into Python\n+equivalents. The few classes that are not wrapped are typically\n+limited to abstract base classes that cannot be instantiated or\n+classes that are meant for internal use in VTK.\n+\n+Python Wrapping Infrastructure\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Python classes for VTK classes and special types are generated using a\n+shared lex/yacc-based parser tailored for VTK programming conventions\n+and custom code generation utilities for Python wrapping. VTK is\n+organized into a number of C++ modules. When built with shared\n+libraries enabled, a library containing C++ classes is generated at\n+build time for each module.  Each Python-wrapped source file is\n+likewise compiled into a shared library corresponding to the C++\n+module. All VTK C++ modules are provided in a single ``vtk`` Python\n+module.\n+\n+VTK Usage in Python\n+~~~~~~~~~~~~~~~~~~~~~~~\n+\n+VTK is provided as a single ``vtk`` module that can be imported like\n+any other module. When building VTK from source, if Python support is\n+enabled, the build process will produce an executable named\n+``vtkpython``. This is the standard Python executable with environment\n+variables set to make it simple to import the ``vtk`` module. It is\n+also possible to use the same ``python`` executable from the Python\n+installation against which VTK was built by prepending the location of\n+VTK's shared libraries and the location of VTK's ``__init__.py`` file\n+to the PYTHONPATH environment variable.\n+\n+To access VTK classes, you simply import ``vtk``:\n+\n+.. code-block:: python\n+\n+   import vtk\n+\n+Creation of VTK objects is straightforward:\n+\n+.. code-block:: python\n+\n+   contourFilter = vtk.vtkContourFilter()\n+\n+Each Python object references an underlying VTK object.  Objects in\n+VTK are reference counted and automatically deleted when no longer\n+used. The wrapping interface updates the underlying VTK object's\n+reference count and alleviates the need for explicit memory\n+management within Python.\n+\n+One particularly nice semantic equivalence between VTK's C++ and\n+Python interfaces involves methods that accept a pointer to a C++\n+array representing a small tuple of elements. Such methods are common\n+in VTK to, for instance, set a 3D Cartesian coordinate as a property\n+of a class. In Python, the corresponding method accepts a tuple or\n+list object. This works well as long as the list or tuple has the\n+expected number of elements.\n+\n+.. code-block:: python\n+\n+   sphere = vtk.vtkSphereSource()\n+\n+   # Express point as list\n+   sphere.SetCenter([0, 1, 0])\n+\n+   # Express point as tuple\n+   sphere.SetCenter((0, 1, 0))\n+\n+Methods that return pointers to arrays with a fixed number of elements\n+are also supported. Such methods require a hint to the wrapping\n+infrastructure indicating how many elements are in the tuple that is\n+returned.\n+\n+.. code-block:: python\n+\n+   >>> center = sphere.GetCenter()\n+   >>> print center\n+   (0, 1, 0)\n+\n+For VTK classes that have operators ``<``, ``<=``, ``==``, ``>=``, ``>``\n+defined, equivalent Python operators are provided.\n+\n+Some class methods in VTK return information via parameters passed by\n+reference. For example, in the following code block, the parameter\n+``t`` is a return parameter from the method ``IntersectWithLine``.\n+\n+.. code-block:: c++\n+\n+   double t, x[3]\n+   plane->IntersectWithLine(point1, point2, t, x);\n+\n+In Python, the equivalent is\n+\n+.. code-block:: python\n+\n+   t = mutable(0.0)\n+   plane.IntersectWithLine(point1, point2, t, x)\n+\n+Class and method documentation is processed by the wrapping\n+infrastructure to make it available via Python's built-in help system.\n+\n+.. code-block:: python\n+\n+   >>> help(vtk.vtkSphereSource)\n+\n+The above shows the full documentation of the ``vtkSphereSource``\n+class (too extensive to list here), while the code below produces help\n+for only the ``SetCenter`` method.\n+\n+.. code-block:: python\n+\n+   >>> help(vtk.vtkSphereSource.SetCenter)\n+\n+   Help on built-in function SetCenter:\n+\n+   SetCenter(...)\n+       V.SetCenter(float, float, float)\n+       C++: void SetCenter(double, double, double)\n+       V.SetCenter((float, float, float))\n+       C++: void SetCenter(double a[3])\n+\n+Some less often used mappings between C++ and Python semantics, as\n+well as limitations, are described in the file\n+``VTK/Wrapping/Python/README_WRAP.txt`` in the VTK source code\n+repository in versions 4.2 and above.\n+\n+Integration with NumPy\n+~~~~~~~~~~~~~~~~~~~~~~\n+\n+In VTK, data set attributes are stored in instances of a subclass of\n+``vtkAbstractArray``. For data sets with points and cells such as\n+``vtkPolyData`` and ``vtkUnstructuredGrid``, attributes can be\n+associated with points or cells, or the data set itself. For point-\n+and cell-associated arrays, each array element is the attribute value\n+associated with the point or cell at the same index. Attribute arrays\n+associated only with the data set can contain arrays of arbitrary size\n+and no mapping between array elements and topological elements of the\n+data set is assumed.\n+\n+There are limited functions within VTK itself to process or analyze\n+these arrays. Since 2008, a low-level interface layer between VTK\n+arrays and NumPy array has been available in VTK. This interface layer\n+can be used to map VTK arrays to NumPy arrays and vice versa, enabling\n+the full power of NumPy operations to be used on VTK data. For\n+example, suppose that we have a data set from a computational fluid\n+dynamics simulation that we can load with a VTK reader class, and\n+suppose further that the data set has a point-associated array\n+representing pressure. We can find several properties of this array\n+using NumPy, e.g.,\n+\n+.. code-block:: python\n+\n+   import numpy as np\n+   import vtk.util.numpy_support as nps\n+\n+   # Load data with VTK reader\n+   reader.Update()\n+\n+   ds = reader.GetOutput()\n+   pd = ds.GetPointData()\n+   pressure = pd.GetArray('pressure')\n+   np_pressure = nps.vtk_to_numpy(pressure)\n+\n+   min_p = np.min(np_pressure)\n+   max_p = np.max(np_pressure)\n+\n+This interface can also be used to add data arrays to loaded data\n+sets that can be handed off to VTK for visualization:\n+\n+.. code-block:: python\n+\n+   norm_pressure = (np_pressure - min_pressure) / \\\n+       (max_pressure - min_pressure)\n+   vtk_norm_pressure = np.numpy_to_vtk(norm_pressure, 1)\n+   vtk_norm_pressure.SetName('normalized pressure')\n+   pd.AddArray(vtk_norm_pressure)\n+\n+The second argument to ``np.numpy_to_vtk`` indicates that the NumPy\n+array should be deep copied to the VTK array. This is necessary if no\n+reference to the NumPy array will otherwise be kept. If a reference to\n+the numpy array will be kept, then the second argument can be omitted\n+and the NumPy array will be shallow copied instead, saving memory and\n+time because the array data does not need to be copied.\n+\n+More recently, a higher-level NumPy-like interface layer has been\n+added to VTK. This ``numpy_interface`` was designed to combine the\n+ease of use of NumPy with the distributed memory parallel computing\n+capabilities and broad data set type support of VTK. The\n+straightforward interface between VTK data set arrays and NumPy\n+described above works only when the entire data set is available on\n+one node. However, data sets in VTK may be distributed across\n+different computational nodes in a parallel computer using the Message\n+Passing Interface [Sni99]. In this scenario, global reduction\n+operations using NumPy are not possible. For this reason, a NumPy-like\n+interface has been added to VTK that properly handles distributed data\n+sets [Aya14].\n+\n+A key building block in VTK's ``numpy_interface`` is a set of classes\n+that wrap VTK data set objects to have a more Pythonic interface.\n+\n+.. code-block:: python\n+\n+   import vtk\n+   from vtk.numpy_interface import dataset_adapter as dsa\n+\n+   reader = vtk.vtkXMLPolyDataReader()\n+   reader.SetFileName(filename)\n+   reader.Update()\n+   ds = dsa.WrapDataObject(reader.GetOutput())\n+   \n+In this code, ``ds`` is an instance of a ``dataset_adapter.PolyData``\n+class returned by the ``WrapDataObject`` function to handle the\n+``vtkPolyData`` output of the ``vtkXMLPolyDataReader``. Point- and\n+cell-associated arrays are available in member variables that provide\n+the dictionary interface.\n+\n+.. code-block:: python\n+\n+   >>> ds.PointData.keys()\n+   ['pressure']\n+\n+   >>> pressure = ds.PointData['pressure']\n+\n+Note that the ``pressure`` array here is an instance of ``VTKArray``\n+rather than a ``vtkAbstractArray``. ``VTKArray`` is a wrapper around\n+the VTK array object that inherits from ``numpy.ndarray``. Hence, all\n+the standard ``ndarray`` operations are available on this wrapped\n+array, e.g.,\n+\n+.. code-block:: python\n+\n+   >>> pressure[0]\n+   0.112\n+\n+   >>> pressure[1:4]\n+   VTKArray([34.2432, 47.2342, 38.1211], dtype=float32)\n+\n+   >>> pressure[1:4] + 1\n+   VTKArray([35.2432, 48.2342, 39.1211], dtype=float32)\n+\n+   >>> pressure[pressure > 40]\n+   VTKArray([47.2342], dtype=float32)\n+\n+The ``numpy_interface.algorithms`` module provides additional\n+functionality beyond the array interface.\n+\n+.. code-block:: python\n+\n+   import vtk.numpy_interface.algorithms as algs\n+\n+   >>> algs.min(pressure)\n+   VTKArray(0.1213)\n+\n+   >>> algs.where(pressure > 38)\n+   (array([2, 3]),)\n+\n+In addition to most of the ufuncs provided by NumPy, the\n+``algorithms`` interface provides some functions to access quantities\n+that VTK can compute in the wide variety of data set types (e.g.,\n+surface meshes, unstructured grids, uniform grids, etc.) available in\n+VTK. This can be used to compute, for instance, the total volume of\n+cells in an unstructured grid:\n+\n+.. code-block:: python\n+\n+   >>> cell_volumes = algs.volume(ds)\n+   >>> algs.sum(cell_volumes)\n+   VTKArray(847.02)\n+\n+This example illustrates nicely the power of combining a NumPy-like\n+interface with VTK's uniform API for computing various quantities on\n+different types of data sets.\n+\n+Another distinct advantage of the ``numpy_interface.algorithms``\n+module is that all operations are supported in parallel when data sets\n+are distributed across computational nodes. [Aya14] describes this\n+functionality in more detail.\n+\n+Integration with matplotlib\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+VTK excels at interactive 3D rendering of scientific data. Matplotlib\n+excels at producing publication-quality plots. VTK leverages each\n+toolkit's strengths in two ways.\n+\n+First, as described earlier, convenience functions for exposing VTK\n+data arrays as NumPy arrays are provided in the\n+``vtk.util.numpy_support`` and ``numpy_interface.algorithms``\n+modules. These arrays can be passed to matplotlib plotting functions\n+to produce publication-quality plots.\n+\n+Second, VTK itself incorporates some of matplotlib's rendering\n+capabilities directly when possible. When VTK Python wrapping is\n+enabled and matplotlib is available, VTK uses the\n+``matplotlib.mathtext`` module to render LaTeX math expressions to\n+either ``vtkImageData`` objects that can be displayed as images or to\n+paths that may be rendered to a ``vtkContextView`` object, VTK's\n+version of a canvas.\n+\n+Qt applications with Python\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Python support in VTK is robust enough to create full-featured\n+applications without writing a single line of C++ code. PyQt [PyQt15]\n+(or PySide [PyS15]) provide Python bindings for Qt. A simple PyQt\n+example adapted from an example by Michka Popoff is provided below:\n+\n+.. code-block:: python\n+\n+  import sys\n+  import vtk\n+  from PyQt4 import QtCore, QtGui\n+  from vtk.qt4.QVTKRenderWindowInteractor \\\n+      import QVTKRenderWindowInteractor\n+\n+  class MainWindow(QtGui.QMainWindow):\n+\n+      def __init__(self, parent = None):\n+          QtGui.QMainWindow.__init__(self, parent)\n+\n+          self.frame = QtGui.QFrame()\n+\n+          layout = QtGui.QVBoxLayout()\n+          self.vtkWidget = \\\n+              QVTKRenderWindowInteractor(self.frame)\n+          layout.addWidget(self.vtkWidget)\n+\n+          self.renderer = vtk.vtkRenderer()\n+          rw = self.vtkWidget.GetRenderWindow()\n+          rw.AddRenderer(self.renderer)\n+          self.interactor = rw.GetInteractor()\n+\n+          cylinder = vtk.vtkCylinderSource()\n+          mapper = vtk.vtkPolyDataMapper()\n+          mapper.SetInputConnection( \\\n+              cylinder.GetOutputPort())\n+          actor = vtk.vtkActor()\n+          actor.SetMapper(mapper)\n+\n+          self.renderer.AddActor(actor)\n+          self.renderer.ResetCamera()\n+\n+          self.frame.setLayout(layout)\n+          self.setCentralWidget(self.frame)\n+\n+          self.show()\n+          self.interactor.Initialize()\n+        \n+  if __name__ == \"__main__\":\n+      app = QtGui.QApplication(sys.argv)\n+      window = MainWindow()\n+      sys.exit(app.exec_())\n+\n+This simple application does little besides what is possible with pure\n+VTK code alone. However, this example can easily be expanded to\n+provide interaction through UI elements such as a menu bar, buttons,\n+text entries, sliders, etc.\n+\n+VTK filters defined in Python\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+While VTK sources and filters are available in Python, they cannot be\n+subclassed to create new sources or filters because the virtual\n+function table defined in C++ does not know about methods defined in\n+Python. Instead, one can subclass from a special ``VTKAlgorithm``\n+class defined in ``vtk.util.vtkAlgorithm``. This class specifies the\n+interface for classes that interact with ``vtkPythonAlgorithm``, a C++\n+class that delegates the primary VTK pipeline update methods to\n+equivalent pipeline update methods in the Python ``VTKAlgorithm``\n+class. Subclasses of ``VTKAlgorithm`` can (and usually should)\n+override these methods. By doing this, it is possible to implement\n+complex new sources and filters using Python alone. For more details\n+on the ``VTKAlgorithm`` class, see [Gev2014].\n+\n+Python integration in VTK tests\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+As a project that follows a quality-software process, VTK has many\n+regression tests. At present, 26% of tests (544 out of 2046) are\n+written in Python. This integration of Python in VTK's testing\n+infrastructure shows how important Python is in VTK's development.\n+\n+\n+Python and ParaView\n+-------------------\n+\n+While ParaView may be built without supporting it, Python is\n+integrated into ParaView in a number of ways. This section provides an\n+overview of this integration.\n+\n+Python Console\n+~~~~~~~~~~~~~~\n+\n+ParaView includes a Python console available under the ``Tools -> Python\n+Console`` menu item. This console is a fully-featured Python console with\n+the environment set up so that the ``vtk`` module is available as well as\n+a number of modules from ParaView itself. When first started, the command\n+\n+.. code-block:: python\n+\n+   from paraview.simple import *\n+\n+is automatically executed to import the ``paraview.simple``\n+module. This module provides a simplified layer of Python functions to\n+execute common commands in ParaView such as file reading, filter\n+creation, and chaining filters together to produce data\n+transformations and visualizations. This layer is described in more\n+detail later.\n+\n+Running commands in ParaView's Python console is identical to running\n+commands in other Python consoles. The key difference is that commands\n+can be used to change the state of the ParaView application. This\n+gives a similar experience to using a Python console to change\n+matplotlib plots.\n+\n+Another way to interact with the Python console is by loading a Python\n+script with ParaView commands to be executed. This feature is ideal\n+for Python script development for ParaView. A button within the Python\n+console brings up a file dialog used to select the Python script to\n+run.\n+\n+\n+Simple Layer\n+~~~~~~~~~~~~\n+\n+ParaView can be run in several difference client/server\n+configurations. In a number of configurations, the client software\n+running on a local workstation connects to a remote process running on\n+a high-performance computing resource. In most cases, VTK objects of\n+the same type, such as a filter, exist on all processes in the overall\n+ParaView application. Because most VTK classes do not know how to\n+communicate among themselves, ParaView wraps designated VTK classes in\n+proxy classes that are able to communicate with each other among\n+distributed processes.\n+\n+The proxy layer is exposed in the ``paraview.servermanager`` Python\n+module. This module provides direct access to a proxy manager\n+class. It can be used to create sources and filters\n+\n+.. code-block:: python\n+\n+  from paraview import sm\n+\n+  pm = sm.vtkSMProxyManager.GetProxyManager()\n+  controller = \\\n+      sm.vtkSMParaViewPipelineControllerWithRendering()\n+\n+  ss = pm.NewProxy('sources', 'SphereSource')\n+  ss.GetProperty('Radius').SetElement(0, 2.0)\n+  controller.RegisterPipelineProxy(ss)\n+\n+  view = pm.GetProxy('views', 'RenderView1')\n+  rep = view.CreateDefaultRepresentation(ss, 0)\n+  controller.RegisterRepresentationProxy(rep)\n+  rep.GetProperty('Input').SetInputConnection(0, ss, 0)\n+  rep.GetProperty('Visibility').SetElement(0, 1)\n+\n+  controller.Show(ss, 0, view)\n+  view.ResetCamera()\n+  view.StillRender()\n+\n+Creating a new data source, a representation for it (how it is\n+rendered), and adding the representation to the view (where it is\n+rendered), is an involved process. The ``paraview.simple`` layer\n+simplifies this process with a set of high-level functions that\n+take care of most of the tedium. The same example above expressed\n+in ``paraview.simple`` functions is reduced to\n+\n+.. code-block:: python\n+\n+   ss = Sphere(Radius=2.0)\n+   sd = Show(ss, rv)\n+\n+Python State Files\n+~~~~~~~~~~~~~~~~~~\n+\n+ParaView is able to save the current state of data, filters, and\n+rendering parameters to a Python source file that, when executed,\n+recreates the currrent state in ParaView. The Python state file is\n+generated in terms of ``paraview.simple`` module functions.\n+\n+Python Tracing\n+~~~~~~~~~~~~~~\n+\n+In addition to saving a snapshot of ParaView's state, live tracing of\n+user interactions with the ParaView user interface is also supported.\n+Each time a user performs an interaction that modifies ParaView's\n+state, Python code is generated that captures the event. This is\n+implemented via instrumenting the ParaView application with Python\n+generation code at various event handlers. The tracing mechanism can\n+record either the entire state of proxies or just modifications of\n+state to non-default values to reduce the trace size. It is also\n+possible to show the trace code as it is being generating, which can\n+be a useful way to learn Python scripting in ParaView.\n+\n+One of ParaView's strenghts is the ability to connect data sources and\n+filters together into a workflow to perform some action. For example,\n+in scientific computing it is not uncommon to convert one file format\n+to another. If ParaView can read the source file format and write the\n+desitnation file format, it is easy to perform the conversion manually\n+with the ParaView user interface. For a large list of files, though, a\n+more automated approach is useful. The Python tracing mechanism\n+provides a way to generate a conversion script by performing actions in\n+the user interface, generating a trace, and then modifying the trace to\n+apply to a series of files that need to be converted.\n+\n+pvpython and pvbatch\n+~~~~~~~~~~~~~~~~~~~~\n+\n+Python scripts generated by either saving the state or tracing may be\n+used through the user interface. For offline data processing or\n+visualization, it may not be necessary or desirable to run the\n+ParaView user interface. In fact, it may not be possible to run the UI\n+if the system does not have Qt available. Two utility programs in the\n+ParaView application suite are provided for this\n+scenario. ``pvpython`` is a Python executable that can be used to run\n+Python scripts. It also serves as an interactive Python shell if not\n+supplied with a Python script argument. ``pvbatch`` is a\n+non-interactive executable that executes a Python script and is\n+intended to perform offline data processing and visualization\n+generation. Both ``pvpython`` and ``pvbatch`` can connect to remote\n+servers for parallel visualization.\n+\n+\n+Python Calculator\n+~~~~~~~~~~~~~~~~~\n+\n+ParaView's Python Calculator filter provides a way to compute\n+additional point-based or cell-based data set attributes using NumPy\n+or the ``numpy_interface.algorithms`` module. This expression will\n+compute the norm of the Normal array associated with points:\n+\n+.. code-block:: python\n+\n+   numpy.linalg.norm(inputs[0].PointData['Normals'], \\\n+                     axis=1)\n+\n+Under the covers, the Python Calculator uses the\n+``vtk.numpy_interface.dataset_adapter`` module to wrap the inputs to\n+the filter. This provides compatibility between VTK arrays and\n+NumPy. All the wrapped input data sets are appended to a list named\n+``inputs`` that is available in the environment in which the Python\n+expression is executed.\n+\n+\n+Python Programmable Filter\n+~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+ParaView provides many data filters for transforming data and\n+performing analysis tasks. However, there are an infinite number of\n+operations one may want to perform on a data set. To address the need\n+for custom filters, ParaView supports a rich plugin architecture that\n+makes it possible to create additional filters in C++. Unfortunately,\n+creating a plugin this way is a relatively involved process.\n+\n+Aside from the C++ plugin architecture, ParaView provides a\n+Programmable Filter that enables a potentially faster plugin\n+development path. This filter is more versatile than the Python","path":"papers/cory_quammen/cory_quammen.rst","position":632,"original_position":632,"commit_id":"9f719cdb8ab8ebcbd08fc746123357c66cd31589","original_commit_id":"9f719cdb8ab8ebcbd08fc746123357c66cd31589","user":{"login":"prabhuramachandran","id":272585,"avatar_url":"https://avatars.githubusercontent.com/u/272585?v=3","gravatar_id":"","url":"https://api.github.com/users/prabhuramachandran","html_url":"https://github.com/prabhuramachandran","followers_url":"https://api.github.com/users/prabhuramachandran/followers","following_url":"https://api.github.com/users/prabhuramachandran/following{/other_user}","gists_url":"https://api.github.com/users/prabhuramachandran/gists{/gist_id}","starred_url":"https://api.github.com/users/prabhuramachandran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prabhuramachandran/subscriptions","organizations_url":"https://api.github.com/users/prabhuramachandran/orgs","repos_url":"https://api.github.com/users/prabhuramachandran/repos","events_url":"https://api.github.com/users/prabhuramachandran/events{/privacy}","received_events_url":"https://api.github.com/users/prabhuramachandran/received_events","type":"User","site_admin":false},"body":"What are the downsides of this path (apart from performance if implemented in pure Python)?  Will these filters work in parallel?  ","created_at":"2015-06-22T19:09:15Z","updated_at":"2015-06-22T19:09:15Z","html_url":"https://github.com/scipy-conference/scipy_proceedings/pull/149#discussion_r32971519","pull_request_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149","_links":{"self":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments/32971519"},"html":{"href":"https://github.com/scipy-conference/scipy_proceedings/pull/149#discussion_r32971519"},"pull_request":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149"}}},"pull_request":{"url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149","id":37757240,"html_url":"https://github.com/scipy-conference/scipy_proceedings/pull/149","diff_url":"https://github.com/scipy-conference/scipy_proceedings/pull/149.diff","patch_url":"https://github.com/scipy-conference/scipy_proceedings/pull/149.patch","issue_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/149","number":149,"state":"open","locked":false,"title":"Paper: Scientific Data Analysis and Visualization with VTK and ParaView (Quammen)","user":{"login":"cquammen","id":360056,"avatar_url":"https://avatars.githubusercontent.com/u/360056?v=3","gravatar_id":"","url":"https://api.github.com/users/cquammen","html_url":"https://github.com/cquammen","followers_url":"https://api.github.com/users/cquammen/followers","following_url":"https://api.github.com/users/cquammen/following{/other_user}","gists_url":"https://api.github.com/users/cquammen/gists{/gist_id}","starred_url":"https://api.github.com/users/cquammen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cquammen/subscriptions","organizations_url":"https://api.github.com/users/cquammen/orgs","repos_url":"https://api.github.com/users/cquammen/repos","events_url":"https://api.github.com/users/cquammen/events{/privacy}","received_events_url":"https://api.github.com/users/cquammen/received_events","type":"User","site_admin":false},"body":"Due to circumstances beyond my control involving a sick child and traveling spouse, I regret to report that this submitted draft is incomplete. I will be working to complete the paper over the next day or two. I am looking forward to this collaborative review process.","created_at":"2015-06-16T03:41:31Z","updated_at":"2015-06-22T19:09:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9566aac3d0301f522988c66d49aa66460986cb77","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149/commits","review_comments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149/comments","review_comment_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments{/number}","comments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/149/comments","statuses_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/statuses/9f719cdb8ab8ebcbd08fc746123357c66cd31589","head":{"label":"cquammen:2015","ref":"2015","sha":"9f719cdb8ab8ebcbd08fc746123357c66cd31589","user":{"login":"cquammen","id":360056,"avatar_url":"https://avatars.githubusercontent.com/u/360056?v=3","gravatar_id":"","url":"https://api.github.com/users/cquammen","html_url":"https://github.com/cquammen","followers_url":"https://api.github.com/users/cquammen/followers","following_url":"https://api.github.com/users/cquammen/following{/other_user}","gists_url":"https://api.github.com/users/cquammen/gists{/gist_id}","starred_url":"https://api.github.com/users/cquammen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cquammen/subscriptions","organizations_url":"https://api.github.com/users/cquammen/orgs","repos_url":"https://api.github.com/users/cquammen/repos","events_url":"https://api.github.com/users/cquammen/events{/privacy}","received_events_url":"https://api.github.com/users/cquammen/received_events","type":"User","site_admin":false},"repo":{"id":37273970,"name":"scipy_proceedings","full_name":"cquammen/scipy_proceedings","owner":{"login":"cquammen","id":360056,"avatar_url":"https://avatars.githubusercontent.com/u/360056?v=3","gravatar_id":"","url":"https://api.github.com/users/cquammen","html_url":"https://github.com/cquammen","followers_url":"https://api.github.com/users/cquammen/followers","following_url":"https://api.github.com/users/cquammen/following{/other_user}","gists_url":"https://api.github.com/users/cquammen/gists{/gist_id}","starred_url":"https://api.github.com/users/cquammen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cquammen/subscriptions","organizations_url":"https://api.github.com/users/cquammen/orgs","repos_url":"https://api.github.com/users/cquammen/repos","events_url":"https://api.github.com/users/cquammen/events{/privacy}","received_events_url":"https://api.github.com/users/cquammen/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cquammen/scipy_proceedings","description":"Tools used to generate the SciPy conference proceedings","fork":true,"url":"https://api.github.com/repos/cquammen/scipy_proceedings","forks_url":"https://api.github.com/repos/cquammen/scipy_proceedings/forks","keys_url":"https://api.github.com/repos/cquammen/scipy_proceedings/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cquammen/scipy_proceedings/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cquammen/scipy_proceedings/teams","hooks_url":"https://api.github.com/repos/cquammen/scipy_proceedings/hooks","issue_events_url":"https://api.github.com/repos/cquammen/scipy_proceedings/issues/events{/number}","events_url":"https://api.github.com/repos/cquammen/scipy_proceedings/events","assignees_url":"https://api.github.com/repos/cquammen/scipy_proceedings/assignees{/user}","branches_url":"https://api.github.com/repos/cquammen/scipy_proceedings/branches{/branch}","tags_url":"https://api.github.com/repos/cquammen/scipy_proceedings/tags","blobs_url":"https://api.github.com/repos/cquammen/scipy_proceedings/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cquammen/scipy_proceedings/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cquammen/scipy_proceedings/git/refs{/sha}","trees_url":"https://api.github.com/repos/cquammen/scipy_proceedings/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cquammen/scipy_proceedings/statuses/{sha}","languages_url":"https://api.github.com/repos/cquammen/scipy_proceedings/languages","stargazers_url":"https://api.github.com/repos/cquammen/scipy_proceedings/stargazers","contributors_url":"https://api.github.com/repos/cquammen/scipy_proceedings/contributors","subscribers_url":"https://api.github.com/repos/cquammen/scipy_proceedings/subscribers","subscription_url":"https://api.github.com/repos/cquammen/scipy_proceedings/subscription","commits_url":"https://api.github.com/repos/cquammen/scipy_proceedings/commits{/sha}","git_commits_url":"https://api.github.com/repos/cquammen/scipy_proceedings/git/commits{/sha}","comments_url":"https://api.github.com/repos/cquammen/scipy_proceedings/comments{/number}","issue_comment_url":"https://api.github.com/repos/cquammen/scipy_proceedings/issues/comments{/number}","contents_url":"https://api.github.com/repos/cquammen/scipy_proceedings/contents/{+path}","compare_url":"https://api.github.com/repos/cquammen/scipy_proceedings/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cquammen/scipy_proceedings/merges","archive_url":"https://api.github.com/repos/cquammen/scipy_proceedings/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cquammen/scipy_proceedings/downloads","issues_url":"https://api.github.com/repos/cquammen/scipy_proceedings/issues{/number}","pulls_url":"https://api.github.com/repos/cquammen/scipy_proceedings/pulls{/number}","milestones_url":"https://api.github.com/repos/cquammen/scipy_proceedings/milestones{/number}","notifications_url":"https://api.github.com/repos/cquammen/scipy_proceedings/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cquammen/scipy_proceedings/labels{/name}","releases_url":"https://api.github.com/repos/cquammen/scipy_proceedings/releases{/id}","created_at":"2015-06-11T16:55:09Z","updated_at":"2015-06-11T16:55:11Z","pushed_at":"2015-06-22T15:15:13Z","git_url":"git://github.com/cquammen/scipy_proceedings.git","ssh_url":"git@github.com:cquammen/scipy_proceedings.git","clone_url":"https://github.com/cquammen/scipy_proceedings.git","svn_url":"https://github.com/cquammen/scipy_proceedings","homepage":"","size":803,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"scipy-conference:2015","ref":"2015","sha":"e3df71a5659ce32396b7c520b89109716a3210fa","user":{"login":"scipy-conference","id":4884274,"avatar_url":"https://avatars.githubusercontent.com/u/4884274?v=3","gravatar_id":"","url":"https://api.github.com/users/scipy-conference","html_url":"https://github.com/scipy-conference","followers_url":"https://api.github.com/users/scipy-conference/followers","following_url":"https://api.github.com/users/scipy-conference/following{/other_user}","gists_url":"https://api.github.com/users/scipy-conference/gists{/gist_id}","starred_url":"https://api.github.com/users/scipy-conference/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scipy-conference/subscriptions","organizations_url":"https://api.github.com/users/scipy-conference/orgs","repos_url":"https://api.github.com/users/scipy-conference/repos","events_url":"https://api.github.com/users/scipy-conference/events{/privacy}","received_events_url":"https://api.github.com/users/scipy-conference/received_events","type":"Organization","site_admin":false},"repo":{"id":1825629,"name":"scipy_proceedings","full_name":"scipy-conference/scipy_proceedings","owner":{"login":"scipy-conference","id":4884274,"avatar_url":"https://avatars.githubusercontent.com/u/4884274?v=3","gravatar_id":"","url":"https://api.github.com/users/scipy-conference","html_url":"https://github.com/scipy-conference","followers_url":"https://api.github.com/users/scipy-conference/followers","following_url":"https://api.github.com/users/scipy-conference/following{/other_user}","gists_url":"https://api.github.com/users/scipy-conference/gists{/gist_id}","starred_url":"https://api.github.com/users/scipy-conference/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scipy-conference/subscriptions","organizations_url":"https://api.github.com/users/scipy-conference/orgs","repos_url":"https://api.github.com/users/scipy-conference/repos","events_url":"https://api.github.com/users/scipy-conference/events{/privacy}","received_events_url":"https://api.github.com/users/scipy-conference/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/scipy-conference/scipy_proceedings","description":"Tools used to generate the SciPy conference proceedings","fork":false,"url":"https://api.github.com/repos/scipy-conference/scipy_proceedings","forks_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/forks","keys_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/keys{/key_id}","collaborators_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/teams","hooks_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/hooks","issue_events_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/events{/number}","events_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/events","assignees_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/assignees{/user}","branches_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/branches{/branch}","tags_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/tags","blobs_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/refs{/sha}","trees_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/trees{/sha}","statuses_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/statuses/{sha}","languages_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/languages","stargazers_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/stargazers","contributors_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/contributors","subscribers_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/subscribers","subscription_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/subscription","commits_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/commits{/sha}","git_commits_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/commits{/sha}","comments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/comments{/number}","issue_comment_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/comments{/number}","contents_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/contents/{+path}","compare_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/compare/{base}...{head}","merges_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/merges","archive_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/downloads","issues_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues{/number}","pulls_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls{/number}","milestones_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/milestones{/number}","notifications_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/labels{/name}","releases_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/releases{/id}","created_at":"2011-05-31T10:26:48Z","updated_at":"2015-06-22T07:22:47Z","pushed_at":"2015-06-22T17:15:32Z","git_url":"git://github.com/scipy-conference/scipy_proceedings.git","ssh_url":"git@github.com:scipy-conference/scipy_proceedings.git","clone_url":"https://github.com/scipy-conference/scipy_proceedings.git","svn_url":"https://github.com/scipy-conference/scipy_proceedings","homepage":"","size":141802,"stargazers_count":76,"watchers_count":76,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":141,"mirror_url":null,"open_issues_count":39,"forks":141,"open_issues":39,"watchers":76,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149"},"html":{"href":"https://github.com/scipy-conference/scipy_proceedings/pull/149"},"issue":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/149"},"comments":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/149/comments"},"review_comments":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149/comments"},"review_comment":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/149/commits"},"statuses":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/statuses/9f719cdb8ab8ebcbd08fc746123357c66cd31589"}}}}