Puzzled by iteration in GH Python components

I have been puzzled with the way GH Python component work.
Basically I was trying to recreate the grasshopper’s “Circle” component - I wanted to have a couple of points as an input (that is more than one point) and then create a circle from those points, with defined radius.
I tried this code:

import rhinoscriptsyntax as rs

a = []
for pt in x:
    circ = rs.AddCircle(pt,y)
    a.append(circ)

And it worked. A list of points is plugged into the “x” GH Python input plug, and a slider float value into the “y” plug. I had to set the “x” input plug to “List Access” instead of “Item Access”, which is I guess obvious because “x” is a list of points.

But on the other side, this code seems to work too:

import rhinoscriptsyntax as rs

a = rs.AddCircle(x,y)

And that is my reason for posting this topic - why does this second code work? There is no “for loop” in it, and we are dealing with a list of points here, not with a single list. I though grasshopper components work on a principle of a iteration, like presented in the first code?

I attached the .gh file with both components.

Thanks you.

circles.gh(2.8 KB)

All GH components are “intelligent” in the sense that they try to detect what is being input and adapt themselves to suit - thus you can feed most components a single item, a list or a tree and the component itself will create the implied loops and output the result as an object, list, or tree…

The python component works the same way, so you are best off writing the script as if it was only one item to process and let it create the loops itself if you feed it a list. You can write your own loops but it can also be tricky - this has been discussed a few times on the Grasshopper forum. It also means you might be removing the automatic intelligence of the component and restrict it to only one type of input.

–Mitch

1 Like

Hi Mitch,

Thank you for the quick reply.

What do you mean by “restrict it to only one type of input”?

I am apologizing for posting the third message in a row, but there is definitively some part about this ghPython intelligence behavior I do not understand.
Here is an example.
I have a 2 python components, both take 5 referenced points from Rhino as an input.

  1. first python component:
    “pts” input is set to “Item access”:
import rhinoscriptsyntax as rs

movedPts = rs.MoveObject(pts,[10,0,0])
a = movedPts

print movedPts

2). second python component:
“pts” input is set to “List access”:

import rhinoscriptsyntax as rs

movedPts = []
for pt in pts:
    movedPt = rs.MoveObject(pt,[10,0,0])
    movedPts.append(movedPt)
a = movedPts

print movedPts

Both components output the same result through “a”.
But inside them, happens something I do not understand: when asked to print the “movedPts” variable, in second python component - all guids from “movedPts” list get printed. Which is ok.
But when I do the same thing at first python component (print movedPts), I only get guid of the last point. This makes my movedPts variable completely useless if I would have to use it further in coding.
What did I do wrong here?

Thank you for the reply.

item vs list access.gh (8.7 KB)

item_vs_list_access.3dm (28.2 KB)

Hi Djordje

please allow me to be very clear about what Mitch already said. The implied iteration that you see at work here is how every Grasshopper component works. Of course, it takes a bit of pain to switch from being a Grasshopper user to a Grasshopper algorithm writer, so many people struggle with this logic at first. This “puzzle” you feel is caused by the curiosity to explore an area that you do not know. Please take this with ease and allow yourself some time to get used to things. Try to tackle this with a fresh mind and not while tired, late at night. Sometimes these tricks help me.

So – the most important thing to realize is that you can write the logic for a single item (say, a single point), a whole list, or several lists together (with a tree). You should always try to write the algorithm with the simplest logic possible, and let Grasshopper match data structures for you. This data-matching algorithm is a tough one, written for you by a “bitsmith” called David Rutten. You should try to exploit that nice logic that is there – let’s not try to reinvent the wheel – and, if you are moving a point, always write the code that takes a point and a vector. Mostapha answered another user quite nicely in this discussion here on Grasshopper.

One thing that seem to obstruct the overview in this case is the visualization of prints in the Editor, when these prints happen sequentially. We could do something about this. I’ve added an item to the bugtracker, to make sure we consider doing something about the Editor print window, so that it shows in some other way several major iterations:

One consideration, additionally: do not use the print feature to return data. Use result variables instead.

In the image above here, you get a tree in (out), and list of points in (a). This is because (a) matches the same layout as the one we have for the (pts) input. But print() could be called several times in one code iteration. The matching algorithm takes that into account, and creates a one-deeper nested list (a tree).

I hope this is helpful,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

2 Likes

Hi Giulio,

Thank you for the quick reply.
Had one and a half hour of sleep this afternoon, so I hope you won’t get mad if I reply right now :slight_smile:
To be honest - I still do not get it. And took a look at your and Mostapha’s replies too.
I do know now that “print” feature has somewhat different way of executing inside of component. I will just leave it that way.
And my intention of using print was not to return data, just to somehow show, what I have inside of “movedPts” variable, when being used inside ghPython component. But as you said, that’s an incorrect way as print and variables have different “type” of executing. Did not know that, sorry.

It seems that once the list of data has been imported into ghPython component with an item access, it no longer acts as a list, neither it could be iterated. And not only that input variable, but variables that were made from that one also. Maybe it’s better if I post an example:

I have some curves from Rhino. What I want to is to reference them from ghPython component, get their starting points, and then construct a separate lines between those points, like this:

  1. If I import those Rhino curves into ghPython component as List access, everything works alright (I do not have “a” as output but “stPts” and “lines”):
import rhinoscriptsyntax as rs

# create start points
stPts = []
for crv in curves:
    stPt = rs.CurveStartPoint(crv)
    stPts.append(stPt)

# create lines from those start points
lines = []
for i in range(len(stPts)-1):
    line = rs.AddLine(stPts[i],stPts[i+1])
    lines.append(line)

  1. a) But if I import “curves” with an Item access they are no longer iterable:
import rhinoscriptsyntax as rs

# create start points
stPts = rs.CurveStartPoint(curves)

# create lines from those start points
lines = []
for i in range(len(stPts)-1):
    line = rs.AddLine(stPts[i],stPts[i+1])
    lines.append(line)

  1. b) And further what made me more confused, is that rs.AddPolyline() function, won’t even accept the “stPts” variable:
import rhinoscriptsyntax as rs

# create start points
stPts = rs.CurveStartPoint(curves)

# create lines from those start points
polyline = rs.AddPolyline(stPts)
lines = rs.ExplodeCurves(polyline)

Why is that so? Because Rhino.Geometry.Polyline() is expecting a list as an argument, which “stPts” is not?

Thank you.

item vs list access2.gh (6.7 KB)
items vs list access 2.3dm (30.2 KB)

Hi Djordje

it seems you are getting fairly close to understanding this, and would just like some reassurance. So, there’s nothing strange in your code, in ghPython, or in what you are trying to do. If you write an algorithm that depends from having all curves together, in a list, you will need List Access. There’s nothing smart you can do to avoid it.

So, answering 2) a) : *But if I import “curves” with an Item access they are no longer iterable: *

Of course. That’s what Item access is. One item every time. Of course one curve item is not iterable. Item access means: give me everything, one item at a time. Nothing more, nothing less.

2) b) rs.AddPolyline() function, won’t even accept the “stPts” variable:
No, it won’t. stPts could also rather be called “stPt”. It’s a single point. Not a list, with Item Access.

Because Rhino.Geometry.Polyline() is expecting a list as an argument, which “stPts” is not?

Yes, exactly. Although you can call variables in any way you want, stPts is still a single point. It’s the Grasshopper component itself that iterates your whole code several times, to make data go in the right spot in the output tree.

The next release of ghPython will show a more advanced preview of the prints, which includes also lines that point out that new implicit cycles were created for you by Grasshopper.

I hope this helps,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

I think I am starting to get it (at least hope I so).
And that new print feature sounds great (hey, that was so fast!).

What can I say: thank you once again Giulio - for both quick and informative replies.

Hi!

Was this new print behaviour implemented in ghpython for rhino5? I saw that the WIP implementation comes with some fancy tricks under the hood but I haven’t seen any of those in the rh5 version. Is there any hope for that release to happen before RH6 release? Anyway, I understand that all the efforts are centered in the Rhino WIP…

Sorry for bumping up this old post.

No problem.

I know, I know, it would be nice to have it generally already available, etc. Also the compiler feature. Well, presently there are no plans for back-porting this functionality. It is available in the WIP.

Hi! Thanks for the reply.

It was what I suppose. Anyway I could copy paste from RH5 and “debug” using this new features…it’s only going to be painful if I hit some not found/solved bugs on my way.

So…is there any documentation about that compiled ghPython component option in WIP?

Cheers.

UPDATE: Don’t worry I’ve found out how to use it and I’m running some simple performance tests.