code runs in VScode, but not in Dynamo embedded python - python

i’m trying to connect a module that provides a straight skeleton algorithm to the embedded python in Autodesk Revit's Dynamo environment.
i’m trying to debug things in VS code using a serialized data from Revit, so i think i have VScode using the embedded python that runs in dynamo.
my test code runs in VScode. Dynamo is able to find the module.
i’m trying to bring it over incrementally. when i add in the line that actually calls the function, i get this error:
Warning: RuntimeError : generator raised StopIteration [' File "<string>", line 40, in <module>\n', ' File "C:\\Users\\mclough\\src\\polyskel2\\polyskel\\polyskel.py", line 437, in skeletonize\n slav = _SLAV(polygon, holes)\n', ' File "C:\\Users\\mclough\\src\\polyskel2\\polyskel\\polyskel.py", line 207, in __init__\n self._original_edges = [_OriginalEdge(LineSegment2(vertex.prev.point, vertex.point), vertex.prev.bisector, vertex.bisector) for vertex in chain.from_iterable(self._lavs)]\n', ' File "C:\\Users\\mclough\\src\\polyskel2\\polyskel\\polyskel.py", line 207, in <listcomp>\n self._original_edges = [_OriginalEdge(LineSegment2(vertex.prev.point, vertex.point), vertex.prev.bisector, vertex.bisector) for vertex in chain.from_iterable(self._lavs)]\n']
i did debug this error (or a similar one?) in VScode, which seems to be related to changes in python 3.8. Is it maybe possible that Dynamo’s embedded python is somehow looking at an old version of the file? Just seems weird that it runs in VScode, but not in dynamo when both versions of python are the same.
I don't understand how i'm supposed to interpret the last line in the Error. I don't see anything that generates a StopIteration exception. The only thing i'm thinking about is the call of 'chain.from_iterable', which is part of itertools. Does it make any sense that would be the issue?
Code from the python node:
`
# Load the Python Standard and DesignScript Libraries
import sys
import clr
#this is temporary. final path should be the KS 'common lib'
sys.path.append(r'C:\Users\mclough\src\polyskel2\polyskel')
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
#sys.path.append(r'C:\ProgramData\Anaconda3\envs\Dynamo212\Lib\site-packages')
import polyskel
#import skgeom as sg
# The inputs to this node will be stored as a list in the IN variables.
# input data is serialized geometry of surface polycurves
# first element is coordinates of the boundary, listed counterclockwise
# remainder elements describe any holes, listed clockwise.
data = IN[0]
# Place your code below this line
skeletons=[]
for shape in data:
bdyPoints = []
boundary = shape.pop(0)
for b in boundary:
x,y=b[0]
bdyPoints.append([float(x),float(y)])
#remaining entries are the holes
holes = []
for curve in shape:
hlePoints=[]
for h in curve:
x,y = h[0]
hlePoints.append([float(x),float(y)])
holes.append(hlePoints)
sk = polyskel.skeletonize(bdyPoints,holes)
#shapes.append([bdyPoints,holes])
skeletons.append(sk)
# Assign your output to the OUT variable.
OUT = []
`
I've checked that VScode and Dynamo are using the same version of python.
I'm using the same input (geometry) data in both instances.
I verified that the modules are discoverable in both environments
I've searched for information on the Runtime Error

Related

How do I get Python Script to draw a simple line in Adobe Illustrator and Visual Studio Code

Like the title says, I just can't get Python script to draw a line between two points in Adobe Illustrator. The following code keeps generating errors:
from os import linesep
import win32com.client as win32com
app = win32com.GetActiveObject("Illustrator.Application")
docRef = app.Documents.Add()
app.Documents.Add()
myLine = docRef.PathItems.Add()
myLine.Stroked = True
myLine.StrokeWidth =5
myLine.SetEntirePath([[10.,20.], [30, 70]]) #fails here
There are other options that I prefer not to use, due to wanting to learn Python in this process.
VBScript, JavaScript and AppleScript have documentation, but Python has the speed and is recommended because it can handle opening and closing files on my computer.
I have tried just about every permutation of the array inside the line that says:
myLine.SetEntirePath([[10.,20.], [30, 70]]) #fails here
but nothing works. Usually I get the error,
Traceback (most recent call last):
File "c:\Users\User\Documents\code\python_illustrator_api\test_com_interface.py", line 41, in <module>
myLine.SetEntirePath([[10.,20.], [30, 70]])
File "<COMObject Add>", line 2, in SetEntirePath
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, 'Adobe Illustrator', 'Illegal argument - argument 1\n- Only arrays with dimension 1 are supported', None, 0, -2147220262), None)
PS C:\Users\User\Documents\code\python_illustrator_api>
This is suggestive that the array is not formatted correctly, but it looks good to me. I have tried just about every possibility: No square brackets, no outer brackets. From what I know of Python, this is the correct format for an array with two X,Y pairs to draw a simple line from the two points.
When I try
myLine.SetEntirePath([10.,20.], [50., 100.], [100, 30])
I get a different error:
TypeError: SetEntirePath() takes from 1 to 2 positional arguments but 4 were given
That is a little more promising, because it seems to be a more descriptive error. Also, correct me if I'm wrong, but basically, VSCode has no helpful prompting when using Win32com as it talks to an API, right? Basically, errors can come from Adobe Illustrator, but there are no helpful suggestions like other versions of Visual Studio.
I have also tried using an array using numpy, but that doesn't work either.
import numpy as np
array1 = np.array([[20, 50], [30, 70]])
myLine.SetEntirePath(array1)
What's the problem? Is there some kind of misunderstanding between win32com and Illustrator?
This is a really basic thing to do, get a script to draw a line between two points on Illustrator.
I could perhaps draw a line on an open instance of Adobe Illustrator, grab the line-segment using Python script, and then kind of reverse-engineer the format that the API likes to have its arrays sent to it, but that might have it's own problems.
Shouldn't something work? After all don't all these different languages end up getting processed through the Common Intermediate Language and then send to the API?
Can someone suggest some solution to this?
Thank you in advance
Interesting. Probably the SetEntirePath() method is broken or something, indeed. I didn't manage to get it work with Python as well.
But there is a workaround. pathItems.pathPoints collection has the method Add(), so you can use a loop to add any points with given coordinates to the path this way:
import win32com.client as win32com
app = win32com.GetActiveObject("Illustrator.Application")
doc = app.Documents.Add()
myLine = doc.pathItems.Add()
myLine.stroked = True
myLine.strokeWidth = 5
points = [[10, 20], [50, 100], [100, 30]]
for xy in points:
point = myLine.pathPoints.Add()
point.anchor = xy
point.leftDirection = xy
point.rightDirection = xy
Output:

Use imshow with Matlab Python engine

After building and installing the Python engine shipped with Matlab 2019b in Anaconda
(TestEnvironment) PS C:\Program Files\MATLAB\R2019b\extern\engines\python> C:\Users\USER\Anaconda3\envs\TestEnvironment\python.exe .\setup.py build -b C:\Users\USER\MATLAB\build_temp install
for Python 3.7 I wrote a simple script to test a couple of features I'm interested in:
import matlab.engine as ml_e
# Start Matlab engine
eng = ml_e.start_matlab()
# Load MAT file into engine. The result is a dictionary
mat_file = "samples/lena.mat"
lenaMat = eng.load("samples/lena.mat")
print("Variables found in \"" + mat_file + "\"")
for key in lenaMat.keys():
print(key)
# print(lenaMat["lena512"])
# Use the variable from the MAT file to display it as an image
eng.imshow(lenaMat["lena512"], [])
I have a problem with imshow() (or any similar function that displays a figure in the Matlab GUI on the screen) namely that it shows quickly and then disappears, which - I guess - at least confirms that it is possible to use it. The only possibility to keep it on the screen is to add an infinite loop at the end:
while True:
continue
For obvious reasons this is not a good solution. I am not looking for a conversion of Matlab data to NumPy or similar and displaying it using matplotlib or similar third party libraries (I am aware that SciPy can load MAT files for example). The reason is simple - I would like to use Matlab (including loading whole environments) and for debugging purposes I'd like to be able to show this and that result without having to go through loops and hoops of converting the data manually.

petsc4py: Creating AIJ Matrix from csc_matrix results in TypeError

I am trying to create a petsc-matrix form an already existing csc-matrix. With this in mind I created the following example code:
import numpy as np
import scipy.sparse as sp
import math as math
from petsc4py import PETSc
n=100
A = sp.csc_matrix((n,n),dtype=np.complex128)
print A.shape
A[1:5,:]=1+1j*5*math.pi
p1=A.indptr
p2=A.indices
p3=A.data
petsc_mat = PETSc.Mat().createAIJ(size=A.shape,csr=(p1,p2,p3))
This works perfectly well as long as the matrix only consist of real values. When the matrix is complex running this piece of code results in a
TypeError: Cannot cast array data from dtype('complex128') to dtype('float64') according to the rule 'safe'.
I tried to figure out where the error occurs exactly, but could not make much sense of the traceback:
petsc_mat = PETSc.Mat().createAIJ(size=A.shape,csr=(p1,p2,p3)) File "Mat.pyx", line 265, in petsc4py.PETSc.Mat.createAIJ (src/petsc4py.PETSc.c:98970)
File "petscmat.pxi", line 662, in petsc4py.PETSc.Mat_AllocAIJ (src/petsc4py.PETSc.c:24264)
File "petscmat.pxi", line 633, in petsc4py.PETSc.Mat_AllocAIJ_CSR (src/petsc4py.PETSc.c:23858)
File "arraynpy.pxi", line 136, in petsc4py.PETSc.iarray_s (src/petsc4py.PETSc.c:8048)
File "arraynpy.pxi", line 117, in petsc4py.PETSc.iarray (src/petsc4py.PETSc.c:7771)
Is there an efficient way of creating a petsc matrix (of which i want to retrieve some eigenpairs later) from a complex scipy csc matrix ?
I would be really happy if you guys could help me find my (hopefully not too obvious) mistake.
I had troubles getting PETSc to work, so I configured it more than just once, and in the last run I obviously forgot the option --with-scalar-type=complex.
This is what I should have done:
Either check the log file $PETSC_DIR/arch-linux2-c-opt/conf/configure.log.
Or take a look at the reconfigure-arch-linux2-c-opt.py.
There you can find all options you used to configure PETSc. In case you use SLEPc as well, you also need to recompile it. Now since I added the option (--with-scalar-type=complex) to the reconfigure script and ran it, everything works perfectly fine.

Python troubles

I've been trying to throw together a python program that will align, crop and create an RGB image from HST and VLA .fits data. Unfortunately I've run into a bit of a problem with it continually opening a past file that does not exist in the folder and neither is it opening in the code itself. I've googled and googled and haven't found anything like it, so perhaps it's just common sense to most, but I can't figure it out. Here's the error message:
You can see at the top that the program I'm running has the filename rgbhstvla.py. I'm not sure what the error message means. Here's the python program as well:
import pyfits
import numpy as np
import pylab as py
import img_scale
from pyraf import iraf as ir
fits.open('3c68.fits', readonly)
j_img = pyfits.getdata('230UVIS.fits')
h_img = pyfits.getdata('230IR.fits')
k_img = pyfits.getdata('5GHZ.fits')
jmin,jmax = j_img.mean()+0.75*j_img.std(),j_img.mean()+5*j_img.std()
hmin,hmax = h_img.mean()+0.75*h_img.std(),h_img.mean()+5*h_img.std()
kmin,kmax = k_img.mean()+0.75*k_img.std(),k_img.mean()+5*k_img.std()
img = numpy.zeros((1024,1024,3))
img[:,:,0] = img_scale.asinh(j_img,scale_min=jmin,scale_max=jmax)
img[:,:,1] = img_scale.asinh(h_img,scale_min=hmin,scale_max=hmax)
img[:,:,2] = img_scale.asinh(k_img,scale_min=kmin,scale_max=kmax)
pylab.clf()
pylab.imshow(img)
pylab.show()
(I'm still working on the program since I'm new to python, tips here would be nice as well but they're mostly unnecessary as I'm sure I'll figure it out eventually).
Python cannot find the file 3c68.fits, which is expected to be in the current working directory, C:\Users\Brandon\Desktop\Research. Either make sure the file is in that directory, or provide an absolute path in your code.

How to organize a Python GIS-project with multiple analysis steps?

I just started to use ArcPy to analyse geo-data with ArcGIS. The analysis has different steps, which are to be executed one after the other.
Here is some pseudo-code:
import arcpy
# create a masking variable
mask1 = "mask.shp"
# create a list of raster files
files_to_process = ["raster1.tif", "raster2.tif", "raster3.tif"]
# step 1 (e.g. clipping of each raster to study extent)
for index, item in enumerate(files_to_process):
raster_i = "temp/ras_tem_" + str(index) + ".tif"
arcpy.Clip_management(item, '#', raster_i, mask1)
# step 2 (e.g. change projection of raster files)
...
# step 3 (e.g. calculate some statistics for each raster)
...
etc.
This code works amazingly well so far. However, the raster files are big and some steps take quite long to execute (5-60 minutes). Therefore, I would like to execute those steps only if the input raster data changes. From the GIS-workflow point of view, this shouldn't be a problem, because each step saves a physical result on the hard disk which is then used as input by the next step.
I guess if I want to temporarily disable e.g. step 1, I could simply put a # in front of every line of this step. However, in the real analysis, each step might have a lot of lines of code, and I would therefore prefer to outsource the code of each step into a separate file (e.g. "step1.py", "step2.py",...), and then execute each file.
I experimented with execfile(step1.py), but received the error NameError: global name 'files_to_process' is not defined. It seems that the variables defined in the main script are not automatically passed to scripts called by execfile.
I also tried this, but I received the same error as above.
I'm a total Python newbie (as you might have figured out by the misuse of any Python-related expressions), and I would be very thankful for any advice on how to organize such a GIS project.
I think what you want to do is build each step into a function. These functions can be stored in the same script file or in their own module that gets loaded with the import statement (just like arcpy). The pseudo code would be something like this:
#file 1: steps.py
def step1(input_files):
# step 1 code goes here
print 'step 1 complete'
return
def step2(input_files):
# step 2 code goes here
print 'step 2 complete'
return output # optionally return a derivative here
#...and so on
Then in a second file in the same directory, you can import and call the functions passing the rasters as your inputs.
#file 2: analyze.py
import steps
files_to_process = ["raster1.tif", "raster2.tif", "raster3.tif"]
steps.step1(files_to_process)
#steps.step2(files_to_process) # uncomment this when you're ready for step 2
Now you can selectively call different steps of your code and it only requires commenting/excluding one line instead of a whle chunk of code. Hopefully I understood your question correctly.

Categories