Python script to save/load GH Inputs (sliders, panels, etc)

Sorry for the long post.

I’m working on a Python script that will save all grasshopper inputs into a CSV file, save the input NickName, Guid and Values.

As well a Script that will load the CSV file and update all inputs inside gh.

I’m not a coder, so I’m struggling a little with some of the input components, mainly the ValueList, BooleanToggle and the TableInputs.

on the BooleanToggle:

if type(obj) is gh.Kernel.Special.GH_BooleanToggle:
    print obj.ToggleValue 

I get an error:

GH_BooleanToggle has no attribute ToggleValue

but if you paste the component onto NotePad you can see the name of the attribute, so don’t know how to get this one.

on the ValueList:

I have no idea on how to get the values, I was thinking on getting the amount of list by using ListCount, and than looping to through that range by using obj.ListItem(i).Expression for value and obj.ListItem(i).Name for the name, but I get the same error that the object doesn’t have those attributes.

            #### get all Value List #####
if type(obj) is gh.Kernel.Special.GH_ValueList:
   print obj.ListCount
   for i in range(0,obj.ListCount-1):
        print obj.ListItem[i].Expression
        print obj.ListItem[i].Name

for the Panels, I got it working for both saving and loading, with one small problem. It will load the list values but if you doubleclick on the panel, all strings are together instead of different lines, but only if you double click:

attached my code, hope someone can help me finish this and it will be usefull for everyone as well.
Cheers

Python Read Inputs.gh (13.8 KB)

Are you aware you could retrieve the values of sliders and value lists with Metahopper?

no I didn’t know, is it with save snipet?

Attached is an example for a slider and a value list. Note that on the value list you must format text like this “aaa” with quotation marks

slider_value_list_metahopper.gh (11.9 KB)

I didn’t know about it, but doesn’t really do what I need. I got a massive program with many sliders, panels, etc. that’s is why I when with a script that will save all inputs into a file, instead of an 1 by 1 approach.

and also need the ability to load everything again from a file.

This will also work for batch, looping through a list of CSV files.

Before you go any further, are you aware of the native Solution > Save State functionality:

It allows you to save named states of all/selected sliders, boolean toggles, gene pools etc. You can probably make/save/read these states to file using a script if need be.

1 Like

great I didn’t know about that one, can that be scripted? and exported/imported as a file?

I’m not sure, but would assume so. It looks a bit convoluted though.

It would be pretty straightforward going down the Python path you already on. Iterating the canvas, grabbing say all named sliders, toggles, and panels and their values, stuffing that into a dictionary, and dumping this to a .json file on disk. Which you could then read in another Grasshopper file and set all named sliders, toggles, and panels to the whatever the name/key-value is in the dictionary.

1 Like

I agree, so any idea on how to get the Toggles Values and the Value List? I’m reach my limit on how to solve it

Indeed, here’s a quick example of the first part (i.e. how to get and write slider/toggle/panel data to disk):


211117_WriteNamedObjectDataToDisk_01.gh (7.2 KB) (Edit: Added “pretty print” JSON formatting)

For value lists, have a look at this example:

2 Likes

Hi @AndersDeleuran nice feature and usefull for a case i’m working on.
I try to port it to python3 / Rh8, and add some additional features, like save location and to parse with additional group_filter and the option to include in the json those nodes with or without nicknames. This all works, but it fail on the Toggles. What every i try that list remains empty “toggles”: {}, while it work in your file.

Can’t figure why it doesn’t work on toggles, all other inputs nodes work fine. Would you mind having a fresh perspective why i fail

you use:

    if type(obj) is gh.Kernel.Special.GH_BooleanToggle:
        if obj.NickName and obj.NickName!= "Toggle":
            ghObjects["toggles"][str(obj.NickName)] = bool(obj.Value)

I try:

    elif isinstance(obj, special.GH_BooleanToggle) and is_valid(obj, "Toggle"):
        container["toggles"][clean_name(obj.NickName)] = bool(obj.Value)

250615_WriteNamedObjectDataToDisk_01.gh (17.9 KB)

My Rhino 8 currently crashes when I try to open it, so afraid I can’t check. But I recall seeing a similar issue posted before (i.e. where the Grasshopper canvas object types are different in CPython/Rhino 8). If GhPython or IronPython works, I’d stick with that for now. If that’s not an acceptable solution, you’ll have to check with e.g. @eirannejad. I’m sure he’ll know a workaround.

my apologies, not sure why that happend, nor should it (doesn’t crashes mine at Version 8 SR20.
I;ll paste the full code below just in case

"""
Save named or all input values to JSON (optionally filtered by group)
Author: Adapted by crz_06 from Anders Holden Deleuran
https://discourse.mcneel.com/t/python-script-to-save-load-gh-inputs-sliders-panels-etc/133418/10
"""

import os
import json
import Grasshopper.Kernel.Special as special

doc = ghenv.Component.OnPingDocument()

# Utility functions
def is_valid(obj, default_name):
    if require_nicknames:
        return obj.NickName and obj.NickName.strip() != default_name
    return True

def clean_name(name, fallback="unnamed"):
    return name.strip() if name and name.strip() else fallback

# Determine filter target
filter_name = group_filter_name.strip() if group_filter_name else None
targets = []

if filter_name:
    group = next((g for g in doc.Objects if g.NickName and g.NickName.strip().lower() == filter_name.lower() and hasattr(g, "Objects")), None)
    if group:
        targets = group.Objects()
    else:
        print(f"⚠️ No group found with nickname '{filter_name}'")
        targets = []
else:
    targets = doc.Objects

# Build container for one group or the full canvas
container = {
    "sliders": {},
    "toggles": {},
    "panels": {},
    "valuelists": {}
}

for obj in targets:

    if isinstance(obj, special.GH_NumberSlider) and is_valid(obj, "Slider"):
        container["sliders"][clean_name(obj.NickName)] = float(str(obj.Slider.Value))

    elif isinstance(obj, special.GH_BooleanToggle) and is_valid(obj, "Toggle"):
        container["toggles"][clean_name(obj.NickName)] = bool(obj.Value)

    elif isinstance(obj, special.GH_Panel) and is_valid(obj, "Panel"):
        container["panels"][clean_name(obj.NickName)] = str(obj.UserText)

    elif isinstance(obj, special.GH_ValueList) and is_valid(obj, "Value List"):
        selected = obj.FirstSelectedItem
        value = selected.Name if selected else "none"
        container["valuelists"][clean_name(obj.NickName)] = value

# Wrap container in root structure
label = filter_name if filter_name else "global"
gh_data = {label: container}

# Save to file
if Dump:
    gh_path = doc.FilePath
    if not gh_path:
        print("⚠️ Please save the Grasshopper file first.")
    else:
        gh_folder = os.path.dirname(gh_path)
        gh_name = os.path.splitext(os.path.basename(gh_path))[0]
        state_folder = os.path.join(gh_folder, "state")
        os.makedirs(state_folder, exist_ok=True)
        out_path = os.path.join(state_folder, f"{gh_name}.json")

        with open(out_path, "w", encoding="utf-8") as f:
            json.dump(gh_data, f, indent=4)

        print(f"✅ Saved input state to:\n{out_path}")

Sorry, I see how what I wrote was confusing. What I meant was that my Rhino 8 literally won’t open. Nothing to do with your script :slight_smile:

This might be a little side quest BUT - DKUI, the new cross platform GUI builder for Grasshopper has save/load UI state, both to Rhino doc and/local drive available:

Cheers

DK

I’ve follow your progress closely (i’ve bookmarked your post :wink: )
I know there a various method to save the native state, some with and some without external libraries. In my case, i want to to be native due a company policy, and i’ll do some post-processing with the json file afterwards. So kinda have my hopes on this method to work … so close …

Got my Rhino 8 working again, and the isinstance workaround seems to work on my system:

ok … and if you would be so kind to test try my code again? maybe I by mistake mess up later in the file as my json looks like this

{
    "test": {
        "sliders": {
            "Foo": 0.802,
            "Bar": 0.277,
            "unnamed": 0.216
        },
        "toggles": {},
        "panels": {
            "unnamed": "Troy\r\nAbed",
            "Community": "sxgsghsd\r\nsdgs"
        },
        "valuelists": {
            "List": "Two"
        }
    }
}

Here’s my original file updated to CPython, seems to work as expected:

260616_WriteNamedObjectDataToDisk_CPython_00.gh (8.6 KB)

Hope that helps solve it.

1 Like

thanks :folded_hands:, i’ll try to debug where things went wrongs

1 Like