Developer forum
cancel
Showing results for 
Search instead for 
Did you mean: 

Using AC Python Modules in Grasshopper (IronPython 2.7)

JSN
Booster
Hey,

This topic is actually a bit specific and maybe not totally new but I will give it another try as I am currently always coming back to it again. So afaik Grasshopper is using IronPython which is limited to version 2.7 and the Archicad module cannot be used. Due to the fact that the GH Livebridge is lacking some basic functionalities in terms of usability I have decided to use the Python Wrapper for the JSON Interface to implement some automation features. (e.g. Automatically setting classifications for elements based on Property Information).

However, it would be better to have all the functionalities condensed in one place or in other words it would be very nice if we could use Grasshopper to further customize those snippets as this is way more user friendly to handle for the everyone than to fiddle with the Python scrippts. Sure I could write a GUI for it but it would be much faster and nicer if we could already use the existing setup in the GH template like drop down selection components which contain our property groups and names or the classification names.

The only thing different for the colleagues would be that they are not using standard GH components, but Python Components containing the relevant methods as components ready for use.

Anyhow at the moment I think this is not possible without workarounds that contain big efforts. Sure I could either use the JSON Interface directly but this would take lots of time to set it up and as I think i am not alone who wants such features this is not my task either. So, well probably there are also further developements planned to improve the GH Livebridge itself to make it more GH-like but the past months and years don't make me get to exciting here in my hopes.

Coming back to the actual question, is there any workaround how to achieve what I want and that may slipped trough my attention or is it just not possible at the moment (and in the future) and my best option is to built GUIs for my Python Scripts to make them more human friendly for my colleagues?
17 REPLIES 17

leceta
Enthusiast
Hi JSN, I dont get why the path I showed some weeks ago is not what you are looking for. It's based on IronPython, indeed.

https://archicad-talk.graphisoft.com/viewtopic.php?f=43&t=70565#p321313

Isn't it what you are looking for?

saludos

JSN
Booster
Hi leceta,

You are right, this is indeed a possibility but it would require a complete re-writing of the scripts or as I wrote
Sure I could either use the JSON Interface directly but this would take lots of time to set it up and as I think I am not alone who wants such features this is not my task either.
Probably this is going way faster than I am thinking right now e.g. with a good input dictionary logic and rebuilding the methods with well thought-out loops does the job sooner or later ...
{
    "command": "API.GetElementsByType",
    "parameters": {
        "elementType": "Wall"
    }
}
... but it is still a bit complex and the whole handling is not very good .... probably it would be even easier to access an existing python script which is customized with the help of GH, then saved locally via the filewriter component just to be executed afterwards to make the changes .... yeah I know, does not sound like the shortest way, but that's how it feels ...

So what I am saying is, I have written my scripts in python and it does the job. Reinventing the whole thing now just that other people can use them as well is a bit a showstopper.

Edit: It also seems to be a bit unstable, my canvas just literally went bloody red after the panel looked like it got beaten up badly .... this has never happend before, but it is a kind of funny discovery too

Anyway, seems to be just too much information for the panel - the output works .. but it seems to be still very slow. Iterating Classifications Details for 10 Elements took more than 10 second ... I have about more than 700 ... why is this taking so long here, it is just a simple loop over all my ClassificationitemGuids ...

leceta
Enthusiast
First check, avoid GH to type cast your inputs (select "No Type Hint") type checking slow things considerably, but definitely 10 seconds seems too muchs (unless you have thousands of parameters embedded in your ArchiCAD elements, who knows...)

Second check. Be sure looping over list is commanded by your python logic (foor loops) instead of leting GH component do the job

If you share your python logic I can check it for more suggestions. DM if you prefer. but sharing is a good thing, anyway.

Edit: Oh, and last but not least, in my experience json call from ghpython are veeery slow. This should be made noticed to Graphisoft developers...

JSN
Booster
leceta wrote:
First check, avoid GH to type cast your inputs (select "No Type Hint") type checking slow things considerably, but definitely 10 seconds seems too muchs (unless you have thousands of parameters embedded in your ArchiCAD elements, who knows...)

Second check. Be sure looping over list is commanded by your python logic (foor loops) instead of leting GH component do the job
The Input type is set to >No Type Hint<, actually here it seems like it would not really matter if it is checked for a string either - processing time is pretty much the same.

The logic is simple ...
result = []

request = urllib2.Request ('http://localhost:19723')

for i in x:   
    response = urllib2.urlopen (request, json.dumps(
    {
        "command": "API.GetDetailsOfClassificationItems",
        "parameters": {
            "classificationItemIds": [
                {
                    "classificationItemId": {
                        "guid": i
                    }}]}}).encode("UTF-8"))
    
    result.append (json.loads (response.read ()))
I am looping for all the guid items in x which is a simple list of the Classification Guids as you could see in the screenshot above. To avoid a crash I have limited it to just the first 11 items.

Sure it is sending a request for each guid, but is there a possibility to send it in one shot, I guess not? Plz tell me if there is a more efficient way to do this.

Well, there are lots of properties in the file, but as I am not checking elements but the classifications itself it should not be a problem. Moreover the same loop just takes a second or so in VS Code and afaik it uses the same interface,so ....
leceta wrote:
Edit: Oh, and last but not least, in my experience json call from ghpython are veeery slow. This should be made noticed to Graphisoft developers...
Is this the issue here, or have i just missed something totally out?
Btw, thx for your time!

leceta
Enthusiast
Hi JSN, as you already noticed, it seems that having to make one request for each element is the problem. Did you try to passing a list of guids to the request, instead of sending one each time? it seems possible as seen on the API example

JSN
Booster
Well I tried it with
for i in x:
    guidlist.append(i)

response = urllib2.urlopen (request, json.dumps(

{
    "command": "API.GetDetailsOfClassificationItems",
    "parameters": {
        "classificationItemIds": [
            {
                "classificationItemId": {
                    "guid": guidlist
                }
                }
        ]
    }
}

).encode("UTF-8"))

but this throws me back an error. Any ideas how to this should work?
[{'succeeded': False, 'error': {'code': 4002, 'message': "Invalid command parameters (The JSON is invalid according to the JSON schema. Validation failed on schema rule 'type' while trying to validate field on path '#/classificationItemIds/0/classificationItemId/guid'.)"}}]

leceta
Enthusiast
...

leceta
Enthusiast
I would rather try this...
guidList=[]
fo guid in x:
     guidList.append({"classificationItemId":guid})

response = urllib2.urlopen (request, json.dumps(
{
    "command": "API.GetDetailsOfClassificationItems",
    "parameters": {"classificationItemIds": guidList}
    }

JSN
Booster
Have you tried it out? For me that's not working and it seems like you forgot about the "guid" part.
I think there must be another nested loop as the example command looks like the following ....
{
    "command": "API.GetDetailsOfClassificationItems",
    "parameters": {
        "classificationItemIds": [
            {
                "classificationItemId": {
                    "guid": "0EE23E04-F4FC-4DAA-AE52-01A3B0503050"
                }
            },
            {
                "classificationItemId": {
                    "guid": "8B729AC6-15B1-4F74-8B4F-359D80DA6871"
                }
            },
            {
                "classificationItemId": {
                    "guid": "11111111-2222-3333-4444-555555555555"
                }
            }
        ]
    }
}


Had not time yet to look into it, but I will try to get something closer to this. Anyhow, I think it is just too cumbersome to get everything as desired in GH .... even though it seems to be possible somehow.
            {
                "classificationItemId": {
                    "guid": "0EE23E04-F4FC-4DAA-AE52-01A3B0503050"
                }
            },

leceta
Enthusiast
my bad, I obviate the conversion from python dict to json objects. Here it goes a working version (checked)

code from "Step 3" (see image below)
import json
import urllib2

guid = json.dumps(classSysGuid)

if run:
    req = urllib2.Request('http://localhost:19723')
    response = urllib2.urlopen(req,json.dumps({"command": "API.GetAllClassificationsInSystem","parameters":json.loads(guid)}).encode("UTF-8"))
    response = json.loads(response.read())

    classIds = []
    if response['succeeded']:
        for item in response['result']['classificationItems']:
            for key,dict in item['classificationItem'].items():
                if key == 'classificationItemId':
                    classIds.append({'classificationItemId':dict})

    guids = json.dumps(classIds)
    req = urllib2.Request('http://localhost:19723')
    response = urllib2.urlopen(req,json.dumps({
    "command":"API.GetDetailsOfClassificationItems",
    "parameters":{
        "classificationItemIds":json.loads(guids)
        }
        }).encode('UTF-8'))
    response = json.loads(response.read())
    id = []
    name = []
    description = []
    for item in  response['result']['classificationItems']:
        id.append(item['classificationItem']['id'])
        name.append(item['classificationItem']['name'])
        description.append(item['classificationItem']['description'])
Also sharing the GH file. Note that there is a dependency to a 3rd. party plugin (Human), but Its not necessary for the json logic to work, just used as a convenient UI gadget to select between different classification systems received from Archicad document. There is alternative implemented in the shared gh if you don't want to install Human in your system.

JSN
Booster
Ah yes thx the hint how to convert the dicts to json objects again helps a lot to understand the parsing.
I used it to reformat my guidList (which had no hierachy) to retrieve the ClassificationDetails for all ClassificationItems. So yeah, I will look a bit more into that next week if time allows it. I will come back to you if I encounter the next hurdle 😉

poco2013
Advisor
Hey JSN:

I have been following your posts and am curious as to your intended use of Grasshopper? I see that there was some initial complaint about the slowness of the script. I didn't see any significant difference other than the initial requests time delays. Also, to that point, since the initial request of GetCllasifcationItems returns all the info you are asking -- why then call GetDetails? Also don't see a need for the double conversion of JSON commands?
Finally, Since the script will work just as well within Archicad, any IDE, or Grasshopper, allowing for the change in urllib2 from 2.7 to 3.0+, what is the advantage of Grasshopper? What are you ultimately trying to accomplish that can't be directly done in Archicad or the Archhicad/Grasshopper interface? -- Just asking?

To illustrate my point I have attached a Python Grasshopper script that returns the classifications info with minimal delay.Runs equally well within Archicad -- just change urlib2 to urllib - change from 2.7 to 3.0+
 #import rhinoscriptsyntax as rs
import json
import  urllib2 as rb

#request = rb.Request('http://localhost:19723')
request = 'http://localhost:19723'

response = rb.urlopen(request,json.dumps({"command":"API.GetAllClassificationSystems"}).encode('UTF-8'))
results = json.loads(response.read())
result = results['result']['classificationSystems'][1]['classificationSystemId']['guid']
response.close()

response = rb.urlopen(request,json.dumps({"command":"API.GetAllClassificationsInSystem",
"parameters": {"classificationSystemId": {"guid": result }}}).encode('UTF-8'))
results = json.loads(response.read())
response.close()
seed =results['result']['classificationItems']

output = []
level = 0
def get_ids(seed,kids = 0 ):
    global level
    level += 1
    for item in seed:
        output.append( '   '*(level-1) +  item['classificationItem']['id'])
        if kids >0:
            kids -= 1
        
        if 'children' in item['classificationItem'].keys():
            depth = len(item['classificationItem']['children'])
            get_ids(item['classificationItem']['children'], kids = depth)
        else:
            if kids == 0:
                pass # Debug only
    level -= 1
    
get_ids(seed, kids = 0 )
for x in output:
        print(x)

 
Gerry

Windows 10 - Visual Studio 2019; ArchiCAD 25

leceta
Enthusiast
Even if I have not been asked, let me share my point of view
I personally find interesting the idea of having packed all this tech in the same environment. I found the current state of things... "disgregated". Param-O should be the natural place for all this to happen, but no tinkering possible currently without C++ (afaik). Limited connection with GDL code, no python interface, no GH interface... Sadly, Graphisoft doesn't seem interested in "agglutination", but hopefully time will demonstrate I'm wrong.

With all its performance/stability issues, I think GH connection is currently the most accessible "all-this-tech agglutination" tool, it offers a more powerful interface to couple with GDL code and all the JSON API is there using IronPython, plus the plethora of goodies that offer GH...
Also don't see a need for the double conversion of JSON commands
cool, much better!

JSN
Booster
Hey Gerry,

As leceta already summed it in well wrapped sentences, it's an attempt to unite the fragmented situation we are facing at the moment. There have been discussions in other topics that it is a very welcomed way to open up different interfaces and ways to connect but currently it feels like you need always a different tool for a different workflow task. This makes it very hard to setup a streamlined developement pipeline. Grasshopper is not only very easy to learn and intuitive to use, but it allows you to achieve very fast results. With all it's universal goodies it's simply the weapon of choice.

Anyhow after some time I can say that the JSON API approach with IronPython has kinda served as a proof of concept, it could indeed be used to compensate what the official GH plugin is lacking since the beginning - the possibility to alter existing elements e.g. here more specifically to change classifications based on element property values (but dynamically). Needless to say that it is of course lots of tinkering around. I mean you could write it very use case specific all within one component - as you did very efficiently - or with the more universal building block approach as I did, to have more flexibility. So, well as I said it works and I think there is still some space left for improvements but at the moment I am fine with the speed. Especially because the functionalities are kinda limited at the moment.

So let's hope that the JSON Api will be extended further in the future to be able to automate more and more. Needless to say that it would be of course highly appreciated to see Param-o grow but I think it is a long way to go to reach anywhere near because with the grasshopper experience the bar is set very high ...

poco2013
Advisor
Thanx for the feedback Leceta and JSN:

I mostly agree but getting there is the real problem in my opinion. With the introduction of Python, Param-o ,Grasshopper, MEP, Structural connections, etc., etc. I expect that Graphisoft has taken on more than they can deliver. Small yearly incremental changes in each of these areas will be of no use to anyone. For example, the Present C++ API has approx. 900 functions, The present Python API has 25. At this rate, it would be 50 years before Python would approximate the utility of the C API. and the same is true for the other features.

With respect to Python, Graphisoft's management has already reneged on several promised developments. I do wonder if the small increments and diverse approach is just marketing hype to to tout features that really have little real world utilization because of the limited development effort. In effect, false advertising?

The approach of "lets do a little of everything" will not work and never has. It only promotes features that can not be practically used.This is ultimately going to frustrate users and give Archicad a very bad reputation if some change in philosophy is not demonstrated soon.
Gerry

Windows 10 - Visual Studio 2019; ArchiCAD 25

JSN
Booster
poco2013 wrote:
Graphisoft's management has already reneged on several promised developments. I do wonder if the small increments and diverse approach is just marketing hype to to tout features that really have little real world utilization because of the limited development effort. In effect, false advertising?

The approach of "lets do a little of everything" will not work and never has. It only promotes features that can not be practically used.This is ultimately going to frustrate users and give Archicad a very bad reputation if some change in philosophy is not demonstrated soon.
I am afraid that your assumption is reflecting pretty well what many users already having in their minds ...

leceta
Enthusiast
I mostly agree but getting there is the real problem in my opinion. With the introduction of Python, Param-o ,Grasshopper, MEP, Structural connections, etc., etc. I expect that Graphisoft has taken on more than they can deliver. Small yearly incremental changes in each of these areas will be of no use to anyone. For example, the Present C++ API has approx. 900 functions, The present Python API has 25. At this rate, it would be 50 years before Python would approximate the utility of the C API. and the same is true for the other features.

With respect to Python, Graphisoft's management has already reneged on several promised developments. I do wonder if the small increments and diverse approach is just marketing hype to to tout features that really have little real-world utilization because of the limited development effort. In effect, false advertising?
Yes, as JSN said this is a shared "fear". Graphisoft seems to follow the same pattern, again and again, letting perish lots of great initiatives, but feel bored complaining about all this. The general user complacency, the minimal near to zero contact with ArchiCAD developers... makes the conversation not only boring (because its futility), but also discouraging because one finishes feeling like an annoying troll.

So, fingers crossed, let's see how good they do it this time.

Still looking?

Browse more topics

Back to forum

See latest solutions

Accepted solutions

Start a new discussion!