Open EwoutH opened 1 year ago
So setting global variables, including sliders and switches is very easy with pyNetLogo. Figured it out in 5 minutes, I was looking for a separate function in pyNetLogo but you can just use the .command()
function.
I thought let's update the tutorial quickly, but of course that came crashing down hard. So the rest of the hour was spent trying to fix that, unfortunately to moderate succes. I filed a bug here: https://github.com/quaquel/pyNetLogo/issues/65.
And of course no debug process is complete without an IDE bug and having to roll back PyCharm.
Anyway, the updated tutorial, which crashes halfway, is available here. The main takeaway is, for anyone finding this issue or wanting to use it as reference:
Setting global variables
To run scenarios or experiments, you can directly set NetLogo global variables (including sliders and switches) by using the
.command()
function. For example, you can modify the initial number of sheep by:netlogo.command('set initial-number-sheep 50')
To set many initial variables at once, you can create a dictionary and loop through that using F-strings:
# Create a dictionary with variables and values to set variable_dict = { "initial-number-sheep": 200, "initial-number-wolves": 75, "grass-regrowth-time": 20 } # Loop through them using F-strings for variable, value in variable_dict.items(): netlogo.command(f'set {variable} {value}')
@quaquel I think this part can be a bit clearer in the tutorial. When #65 is fixed, I can open a PR to add it if you like.
I fixed #65 and have already made a few tutorial updates to reflect this fix and other changes. Any additional suggestions for the tutorial are still very welcome.
Do you know if it's also possible to read-out current, minimum and maximum slider values? They are present in the model code, so it should be possible.
That would be a great feature, because then you can just ask to vary though the pre-defined ranges.
How would you query these within NetLogo?
My approach would be to directly take them from the NetLogo model file itself, they are clearly in there:
SLIDER
16
602
245
635
average-parent-contacts-per-child
average-parent-contacts-per-child
0
10
10.0
1
1
NIL
HORIZONTAL
SLIDER
6
922
187
955
chance-of-moving-out
chance-of-moving-out
5
25
15.0
1
1
%
HORIZONTAL
Once you have those you can do all kind of things, filling a hypervolume, sensitive analysis, etc.
So, as far as you know, there is no command or other way to get these numbers out? In that case, it will be hard to get them out to Python without writing a lot of additional novel java code.
No, but I also haven't really searched for it. We can also asked it on the NetLogo repo.
The scope of pynetlogo, as with the mathematical link, is to send NetLogo commands to NetLogo and query reporters. So, if what you want can be done within this scope it is okay. My suggestion would indeed be to check the NetLogo repo.
I dove a bit deeper into this. The thing we need to read out are called the widgets. They are basically all interface elements, but also saved in the .nlogo
file in plain text. So we can also interact with them in headless mode.
There are two general approaches to this.
NetLogoLink.java
that uses the widgets API..nlogo
file.The extending the NetLogoLink.java
could look a bit like this (GPT generated, for inspiration):
And the pure-Python implementation more like this:
Another thing I would like to implement is a collect_monitor_values()
functions, which returns a dictionary with all the values from monitors. That way you can easily collect what you are also observing in the model itself.
The goal from both is to reduce Python code and leave as much of the stuff in NetLogo itself. Given that, you test you NetLogo model with a few lines of code, and if you want to adjust values, you can just start with get_input_properties()
and go from there.
Which approach do you prefer?
One other thing I thought of is that counters are not readable from the NetLogo file in runtime. On the other hand, the counter variable names (reporters) are, so we could add them as reporters automatically of course.
So when choosing an approach, it probably depends on how far we want to scale this.
A pure-Python scraping approach would be feasible to implement for my by myself, a hybrid Java-Python one using the widgets API I can do the Python part.
I am inclined to take the hybrid java route. I expect this to be more robust in the long run.
Is it possible to vary the values of sliders using pyNetLogo? If so how?
In the docs I can only find
.write_NetLogo_attriblist()
, but that seems to modify agent values.