Hey all,
I wanted to share something i’ve built i assume others might find useful.
When using datashapes, I’ve always felt like persistent inputs were missing. So if a user runs the graph with dynamo player twice, you’d need to click all the values each time, while some inputs almost never change. See below as example:
When running the graph for the first time, default values are applied:
You can then set the values however you want and continue.
The next time you run the graph, the default values are set to whatever you’ve set the last time:
This works by using two python scripts, one to save/load a .json file in the user’s appdata folder. The filename is the same as the graph you’re currently using. This python node can be toggled to either save or load a config (you load the config at the start of the run, and overwrite the config at the end with the new user input)
A second python node is used to get the default values and prevent a bunch of errors if you were to do this with OOTB nodes:
The node returns either a value from the loaded config (if the config exists and the index exists) or it supplies the default value like you’d normally would on the datashapes input node. You can also supply the python node with the array of values going into the input node so it returns a default index instead of default value.
The python script for loading/saving config:
# Load the Python Standard and DesignScript Libraries
import sys
import clr
import os
import json
clr.AddReference('DynamoRevitDS')
clr.AddReference('ProtoGeometry')
import Dynamo
from Autodesk.DesignScript.Geometry import *
dynamoRevit = Dynamo.Applications.DynamoRevit()
operation = IN[0]
data = IN[1]
runIt = IN[2]
def get_graph_name():
# Copied this function from John Pierson https://github.com/Amoursol/dynamoPython/blob/master/dynamoAPI/dynamoAPICurrentGraphName.py
dynamoRevit = Dynamo.Applications.DynamoRevit()
currentWorkspace = dynamoRevit.RevitDynamoModel.CurrentWorkspace
# Access current version of Dynamo
version = dynamoRevit.RevitDynamoModel.Version
# Checks version of Dynamo and adjusts output according to version
if version.startswith("1."):
# Gets file name which includes full path
filename = currentWorkspace.FileName
# Splits out file path to just file name
graphName = filename.Split("\\")[-1].Replace(".dyn", "")
elif version.startswith("2."):
graphName = currentWorkspace.Name
else:
# Just returning a string here so this name will be used instead of breaking the rest of the script
graphName = "unsupported version"
return graphName
def get_filepath():
# Generating filepath for the config.json file.
return os.getenv('APPDATA') + "\\Dynamo\\Default Configs\\" + get_graph_name() + ".json"
def get_operation(operation):
if str(operation).lower() == 'save':
return operation
elif str(operation).lower() == 'load':
return operation
else:
return None
def save_config(data):
file_path = get_filepath()
directory = os.path.dirname(file_path)
# Check if the directory exists; if not, create it
if not os.path.exists(directory):
os.makedirs(directory)
# Open the file and write the JSON data
with open(file_path, 'w') as f:
f.write(json.dumps(data))
def load_config():
file_path = get_filepath()
# Check if the file exists
if not os.path.isfile(file_path):
return []
with open(file_path, 'r') as f:
data = json.load(f)
# Ensure the data is a list
if isinstance(data, list):
return data
else:
# Handle unexpected formats
return []
if runIt == True:
if get_operation(operation) == 'save':
if isinstance(data, list) and data:
save_config(data)
OUT = data
else:
OUT = "Data was empty or not valid list."
if get_operation(operation) == 'load':
OUT = load_config()
else:
OUT = "Set runIt to True!"
The python script to return the correct default value:
# Load the Python Standard and DesignScript Libraries
import sys
import clr
import os
data = IN[0]
inputIndex = IN[1]
defaultValue = IN[2]
listOfValues = IN[3]
def get_value_index(value):
if isinstance(listOfValues, list) and value in listOfValues:
return listOfValues.index(value)
else:
return 0
if isinstance(data, list) and data:
if not isinstance(listOfValues, list):
try:
OUT = data[inputIndex]
except IndexError:
OUT = defaultValue
elif isinstance(listOfValues, list):
value = data[inputIndex] if inputIndex < len(data) else defaultValue
OUT = get_value_index(value)
else:
OUT = defaultValue
else:
OUT = defaultValue
I hope it’s helpful for anyone.
Criticism is also welcome
default input saving5.dyn (74.3 KB)