COM Integration/Calling Python code
Requires Analytica Enterprise or higher
You can use the COM Integration functions in Analytica to call code written in the Python programming language. This page illustrates how.
Calling Python code
In this example, we implement an object in Python that can be instantiated and used from your Analytica model. The object instantiates as a COM object (Component Object Model), and is available using the standard COM Integration features of Analytica Enterprise.
The example used here calls a Python function found in the Python scipy.spatial
library to compute a Delaunay tessellation, also know as a Delaunay triangulation, of a set of points in 2-D.
After you implement your Python object, but before you instantiate if from Analytica, you'll need to register the object with Windows, which enables COMCreateObject to find it.
Prerequisites
You'll need to install Python for Windows (this example was developed using Python 3.6), and ensure you have the following Python modules installed in your Python environment:
- win32com
- pythoncom
- comtypes
- winreg
- win32api
- numpy
- scipy
- os
- sys
- time
- Analytica_Python (provided here)
How to install these is beyond the scope of this article (and beyond the scope of Lumina tech support), but is something the Python user community should be able to help you with.
The Python class
The Python code that implements the COM object is as follows:
import numpy as np from scipy.spatial import Delaunay import Analytica_Python class DelaunayCOM: _reg_clsid_ = "{B524651C-71B2-4521-9E9D-8CC470E51B24}" # Do not use this CSLID! Generate your own! _reg_desc_ = "COM component that computes a Delaunay tesselation" _reg_progid_ = "Lumina.DelaunayCOM" _reg_class_spec_ = "DelaunayCOM.DelaunayCOM" _public_methods_ = ['Tessellation','Pause'] _public_attrs_ = ['softspace', 'noCalls'] _readonly_attrs_ = ['noCalls'] def __init__(self): self.softspace = 1 self.noCalls = 0 def Pause(self): Analytica_Python.gBreakPump = True def Tessellation(self,pts): tri = Delaunay(np.array(pts)) return tri.simplices.tolist() Analytica_Python.AddCOMClass(DelaunayCOM) if __name__ == "__main__": Analytica_Python.TopLevelServer()
The Tessellation
method is the method that is actually called. The Pause
method is optional, but is useful when debugging. The Analytica_Python
module contains generic functions that assist with registering the class (or classes if you have more than one) and serving it at runtime. That module shouldn't require customization when you create your own classes.
Special COM members
The class contains several members with information about the COM object.
_reg_clsid_
is a unique class ID, and is required for any object that will be instantiated by Analytica. (It is not required for objects that are returned from methods that are called). When you create your own class, you need to generate your own unique CLSLID -- do not reuse the one shown above, which should only ever be used with the Lumina.DelaunayCOM
object. You can do this from the Online GUID Generator.
_reg_progid_
is the name that will be used from COMCreateObject. _reg_class_spec_
is the name of the Python module that contains this class, plus a dot, plus the name of the class itself. Since this code is saved in a file named "DelaunayCOM.py
, the part before the dot is DelaunayCOM
.
_public_methods_
lists the method that are public -- that can be called from Analytica.
Registration
Before the Python object can be used externally, it must be registered. To do this, open a CMD window as an Administrator (or preferably Anaconda3 CMD window), and CD to your code directory. Make sure that when you type python --version
, that the correct python installation is used. If using Anaconda, make sure you have the environment containing all the prerequisites, etc. Then type:
Python DelaunayCOM.py /regserver
where DelaunayCOM.py
is the name of your code file. This sets the registry settings so that Analytica will be able to find your object.
Analytica side
To instantiate your Python object, call COMCreateObject("Lumina.DelaunayCOM")
. The name of your own custom class, or classes, will be something different, of course (use the same that you used in _reg_progid_
. This call returns a COM object, which appears in a result window as «COM Object»
.
When you evaluate this call to COMCreateObject
and you don't have a Python process already running and listening for DelaunayCOM
objects, a new Python process will be launched. This new process will live until you release the object (or if you instantiate several objects, it will live until they have all been released). Running your object from a Python interpreter interface is discussed below.
You'll probably want to use a variable to hold your object, e.g.,
- Variable py :=
COMCreateObject("Lumina.DelaunayCOM")
Given an array of 2-D points named Pts
indexed by
- Index pt := 1..10
- Index Dim := [1, 2]
which are show here as a graph
the tessellation (triangulation) be calling the COM method using the following Analytica expression
py->Tessellation(COMArray(pts,Pt,Dim) )+1
The result is 2-D. The first index, named .dim1
indexes the resulting triangles, and the second index, named .dim2
, has length 3 and indexes the 3 points defining the vertices of each triangle. Because the Python function refers to the first point as point 0, we add 1.
It is more convenient to use global indexes in Analytica for the two indexes of the result, so we drag indexes to the diagram as follows
- Index Vertex_pt :=
1..3
- Index Triangle :=
ComputedBy(tessellationVertices)
and embellish our definition of tessellationVertices
to reindex the result as follows:
- Local tri := py->Tessellation(COMArray(pts,Pt,Dim) )[@.dim2=@Vertex_pt] + 1;
Triangle := 1..IndexLength(tri.dim1);
tri[@.dim1=@Triangle]
The result is show here
The numbers in the cells are the point numbers. To graph the tessellation, we need to transform those to the coordinates of each point, done here in a new variable named Tessellation_points
:
pts[Pt=tessellationVertices]
After some pivoting and setting poly-area-fill in graph setup, we see the computed triangulation.
Enable comment auto-refresher