adjust attr of CGA rule by python script

6868
8
Jump to solution
02-13-2016 03:27 AM
HangyuChen
New Contributor II

Hi guys,

     I want to test how python attr. and para. api work and adjust "height" by python.

so I wrote cga :

attr height = 10

Lot -->   extrude(height) Mass.

and python script:

def addheight():

    objects= ce.getObjectsFrom(ce.selection, ce.isModel)

    for o in objects:

        print o

        h= ce.getAttribute(o, 'height')

        print h

        addh= h+10

        ce.setAttribute(o, 'height', addh)

I hope it can add 10 on height of each building but it returns None. Through debugging, I found "o" is ok (when I choose 5 shapes, 2 shapes without rules, it can report those 3 shapes assigned with rule) 

However, it shows [ ] no attribute in "o" (by getAtrributeSource).

so How CAN I get the Attribute defined in the rule by myself and use it in Python Script ????

If Possible, Could anyone help me finish this simple python script???   (just get "height" and add 10 then return the value back to adjust building)????

Thanks a lot!!!!

CHEN

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
CherylLau
Esri Regular Contributor

First, attributes should be set on shape objects (instead of models):

objects = ce.getObjectsFrom(ce.selection, ce.isShape)

Second, the rule attribute name should be preceded by "/ce/rule/":

h = ce.getAttribute(o, '/ce/rule/height')

Lastly, rule attributes only appear in the list returned by ce.getAttributeList() if they are user set.  This means we can only set them in Python if we first make them user-set attributes.  There are two options for this.  The first option (a simple workaround) is good if this is just a one time operation that you'd like to do because it involves manually setting the attribute.  The second option is more complicated but will work if you'd like everything to work within the python script without having to set anything manually.  In this case, we make the attributes user-set by way of an extra python script that is run from your first python script.

Option 1:

1) Select your shapes.

2) Set the height attribute in the Inspector to 10.  This is the value it already was set to by the rules, but by resetting it through the Inspector we are making a user-set attribute instead of a rule-set attribute.  The number now appears bold indicating that it is a user set attribute.

3) Now you can run the python script (with the two changes above).

Option 2:

1) Create an export python script.  Right click on the scripts folder -> New -> Python Module -> Select Module:Export (Reporting) and choose a name (e.g. coexport.py).

2) In the finishModel() function, add the following code to make the attribute a user set attribute:

ce.setAttributeSource(shape, "/ce/rule/height", "USER")

3) In your first python script, add some lines (after you get the objects but before the for loop) to run the export script you just created:

expSettings = ScriptExportModelSettings()
expSettings.setScript("coexportscript.py")
ce.export(objects, expSettings)

4) Now you can run the first python script (with the two changes above).

View solution in original post

8 Replies
CherylLau
Esri Regular Contributor

First, attributes should be set on shape objects (instead of models):

objects = ce.getObjectsFrom(ce.selection, ce.isShape)

Second, the rule attribute name should be preceded by "/ce/rule/":

h = ce.getAttribute(o, '/ce/rule/height')

Lastly, rule attributes only appear in the list returned by ce.getAttributeList() if they are user set.  This means we can only set them in Python if we first make them user-set attributes.  There are two options for this.  The first option (a simple workaround) is good if this is just a one time operation that you'd like to do because it involves manually setting the attribute.  The second option is more complicated but will work if you'd like everything to work within the python script without having to set anything manually.  In this case, we make the attributes user-set by way of an extra python script that is run from your first python script.

Option 1:

1) Select your shapes.

2) Set the height attribute in the Inspector to 10.  This is the value it already was set to by the rules, but by resetting it through the Inspector we are making a user-set attribute instead of a rule-set attribute.  The number now appears bold indicating that it is a user set attribute.

3) Now you can run the python script (with the two changes above).

Option 2:

1) Create an export python script.  Right click on the scripts folder -> New -> Python Module -> Select Module:Export (Reporting) and choose a name (e.g. coexport.py).

2) In the finishModel() function, add the following code to make the attribute a user set attribute:

ce.setAttributeSource(shape, "/ce/rule/height", "USER")

3) In your first python script, add some lines (after you get the objects but before the for loop) to run the export script you just created:

expSettings = ScriptExportModelSettings()
expSettings.setScript("coexportscript.py")
ce.export(objects, expSettings)

4) Now you can run the first python script (with the two changes above).

CherylLau
Esri Regular Contributor

Actually, there might be an easier way than Option 2.  It might be possible to just set the source to user in the first python script in which case the second python script is unnecessary.

Option 3

1) In the first python script, do this to set the source to user before setting the value of the attribute:

ce.setAttributeSource(o, "/ce/rule/height", "USER")

ce.setAttribute(o, "/ce/rule/height", addh)

2) Now you can run the python script.

HangyuChen
New Contributor II

Dear Cheryl Lau,

Sorry to disturb you again, recently I tried what you suggested. It work well by Option 1. But when I adopted Option3, I met a problem and I can't fix it. Now code became :

def addh():

    objects = ce.getObjectsFrom( ce.selection, ce.isShape)

    for o in objects:

            h= ce.getAttribute(o, '/ce/rule/height')

            addh = h+5

            ce.setAttributeSource(o,'/ce/rule/height', 'USER')

            ce.setAttribute(o, '/ce/rule/height', addh)

    If I had reset the height attribute once( became user-set once), it will suceed running python script to adjust it but it adjusted user-set value not rule-set value( for ex., I reset it before as 10, then return the value source to rule-set as 6.123456, but after running the script, which use the previous value 10 + 5 = 15 not 6.123456+5 = 11.123456 ). Is it possible for script to read the current value not only the user-set value we set before?

    and if I never reset it or just assign one new shape with this rule, I ran the script and the value showed 'NaH'-- none.

    So for that I consider the problem comes from getAttribute(). The user-set value and rule-set value are independent, which means if I assign one new shape with this rule, the rule-set is 6.123456 but user-set remain empty, so when running script it showed NaH. getAttribute() can only read user-set value, right?

    I want everything work within python script and is it possible to read current value without problems above? And for option2, I don't know why need to export objects??

THANKS!

CHEN

0 Kudos
CherylLau
Esri Regular Contributor

Your guess is correct.  Unfortunately, it is not possible to get rule-set attribute values this way.

However, there is a workaround (which is not so easy) if you need to access the rule-set attribute values.  This involves reporting the attribute's value in the cga code and reading that reported value in python.  Use option 2, and in step 2, add the following code to the finishModel() method:

h = model.getReports()["height"][0]     # get value of height from reports

ce.setAttribute(shape, "/ce/rule/height", h+5)     # add 5 to height

ce.setAttributeSource(shape, "/ce/rule/height", "USER")     # set source to USER (since value doesn't come from rules anymore)

And, report the value of the rule-set attribute height in your cga code:

Lot -->

     extrude(height)

     Mass.

     Reports

Reports -->

     report("height", height)

     NIL

Why do we need to export objects?  No reason really, but this is just the workaround that I found works.  Perhaps there is another way.

HangyuChen
New Contributor II

Cheryl Lau,

    Appriciate it!

   I will try it now!

Thank you!

CHEN

0 Kudos
HangyuChen
New Contributor II

Dear Cheryl Lau,

    Last time I succeed on adjusting attr. Thanks!

    Now I meet new problem on different condition. By  "import" I can import sub-CGA into main-CGA with its attr. Is it possible to get Attribute of sub-CGA by Python Script?

I write two cga:

##### Lot.cga ##### sub-CGA

attr h= 20

Lot--> extrude(h)

##### Box.cga ##### main-CGA

attr h2= 10
import X:"Lot.cga"
import Y:"Lot.cga"

Lot--> split(x){~5:X.Lot|~5:Y.Lot}

##########

As you can see, X and Y come from the same cga "Lot.cga" with attr h. Also main-CGA  "Box.cga" has one attr h2.

all I adjust to USER-Attribute as Fig.

DoubleAttrAPI.png

I try to getAttribute in console, but only h2--> successful show 10,  h --> None.

How can I get these two values of h?

THANKS!

CHEN

0 Kudos
CherylLau
Esri Regular Contributor

You can get and set the values of attributes in imported cga files if the attributes are user-set.

ce.setAttribute(shape, '/ce/rule/X.h', 8)

ce.setAttributeSource(shape, '/ce/rule/X.h', 'USER')

print(ce.getAttribute(shape, '/ce/rule/X.h'))

Just a note:  I don't think there is a need to import the same cga file twice.  You only have to import it once, then you can re-use the X.Lot rule.

Lot --> split(x){~5:X.Lot|~5:X.Lot}

0 Kudos
FanjieKong
New Contributor II

If I want to change the color of roof, how can I do? Thank you.

0 Kudos