How can i save ramps presets without using the "save preset" button from the gear icon?
i have an hda with lots of parameters and i don't want to create a new preset for every ramp i want to save.
Ideal interface would be a drop down menu and a save button next to my ramp parameter.
Could i export the ramp as a json file in my HIP dir and append to that each time i press save? then load the selected ramp from the drop down menu somehow (menu would be populated by the json file).
i am thinking python module but i am not sure about this
if writing the ramps in an external file is the way to go, how would i do that and then read the data back?
Any tips on the workflow would be much appreciated!
Save ramp presets
2432 10 3- papsphilip
- Member
- 385 posts
- Joined: July 2018
- Offline
- papsphilip
- Member
- 385 posts
- Joined: July 2018
- Offline
baby step 1
made a dictionary of the ramp parameters
next step is to make a correct json structure (one entry per ramp point holding pos val and interpolation values) and save it to disk
made a dictionary of the ramp parameters
import json node = kwargs['node'] ramp = node.parm('ramp').multiParmInstances() num = node.parm('ramp').multiParmInstancesPerItem() dict = { 'point': [] } for p in ramp: data = {} for i in range(num): if str(i+1) in p.name(): value = p.eval() name = p.name() data[name] = value dict['point'].append(data) print(dict)
next step is to make a correct json structure (one entry per ramp point holding pos val and interpolation values) and save it to disk
- papsphilip
- Member
- 385 posts
- Joined: July 2018
- Offline
baby step 2
corrected the json structure
next step is to append different ramp presets to the same json
and the step after that is to load them
corrected the json structure
import json node = kwargs['node'] ramp = node.parm('ramp').multiParmInstances() num = node.parm('ramp').multiParmInstancesPerItem() dict = { 'point': [] } for i in range(num): data={} for p in ramp: if str(i+1) in p.name(): value = p.eval() name = p.name() data[name] = value dict['point'].append(data) print(dict)
next step is to append different ramp presets to the same json
and the step after that is to load them
- papsphilip
- Member
- 385 posts
- Joined: July 2018
- Offline
baby step 3
append or overwrite options with pop up window
by the way a different approach to constructing the dictionary was given by tamte aka Tomas Slancik
append or overwrite options with pop up window
import json import os path = hou.hipFile.path().rsplit('/',1)[0] + '/ramp_presets/' if not os.path.exists(path): os.makedirs(path) node=kwargs['node'] parm = node.parm('ramp') ramp = parm.evalAsRamp() interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] keylist = [] for i,key in enumerate(ramp.keys()): data = { "pos": i, "value": ramp.values()[i], "interp": interplookup.index(ramp.basis()[i])} keylist.append(data) dict = { 'ramp_name': keylist } filepath = path + 'test.json' json_data = json.dumps(dict, indent=4) if os.path.isfile(filepath) and os.path.getsize(filepath)>0: #if file exists and is not zero bytes user = hou.ui.displayMessage('a file already exists',buttons=('Append','Overwrite',)) if user==0: with open(filepath,'a') as f: f.write(json_data) if user==1: os.remove(filepath) with open(filepath,'w') as f: f.write(json_data) else: with open(filepath,'w') as f: f.write(json_data)
by the way a different approach to constructing the dictionary was given by tamte aka Tomas Slancik
Edited by papsphilip - Oct. 13, 2021 15:24:50
- papsphilip
- Member
- 385 posts
- Joined: July 2018
- Offline
- Saman_batham
- Member
- 1 posts
- Joined: Dec. 2018
- Offline
- papsphilip
- Member
- 385 posts
- Joined: July 2018
- Offline
- Jikian
- Member
- 141 posts
- Joined: Aug. 2012
- Online
Saman_batham
can we change ramps using a slider is that possible if we have same no. of points in ramp
Ramp parameters are essentially multiparms - you can reference each point's position/value parameter directly if you read the "index" value. If you have a ramp parameter with a fixed number of points, you can channel-reference each point's Value independently.
- Yader
- Member
- 36 posts
- Joined: Feb. 2016
- Offline
papsphilip
after lots of baby steps...
ok i finished the HDA for saving ramp presets and loading them back in.
Thanks a bunch for this, but I get an error message for folder where I have read/write rights:
Traceback (most recent call last):
File "FP::dev::Sop/ramp::1.2/save", line 1, in <module>
File "FP::dev::Sop/ramp::1.2, PythonModule", line 57, in Save
PermissionError: [ErrnoTraceback (most recent call last):
File "
And is it also possible to save RGB ramps?
Thanks in advance!
Edited by Yader - Sept. 9, 2022 05:21:14
- fr_3D
- Member
- 9 posts
- Joined: Nov. 2020
- Offline
Thanks @papsphilip and @tamte for this solution! For an HDA with many parameters I wanted to export all parameters including color and float ramps as well as multiparms, so I extended the script a bit. Now it seems like all standard parameter types are supported. While ramps are detected automatically, for now multiparms need to be manually defined in the script. Does anyone know a way to isolate multiparms in Python?
### Global import json, os # Manually Define Multiparms Here mplist = ['mp_a', 'mp_b', 'mp_c'] # Wrappers for Separating Ramp, Standard and Multiparm Data in the .json File stdgroup = 'standard' rampgroup = 'ramps' mpgroup = 'multiparms' ### Export Parameters def write_params(kwargs): hda = kwargs['node'] params = hda.parmsInFolder(['Parameters']) from sys import platform dir = hda.parm('path').evalAsString() + '/cache/' # Windows and MacOS Handle File Paths Slightly Different if platform == 'darwin': dir = hda.parm('path').evalAsString() + 'cache/' filepath = dir + '_config_' + hda.parm('preset').evalAsString() + '.json' data = {} ramp = {} ramps = {} mp = {} for parm in params: if not parm.isHidden(): # Loop Through Ramp Parameters if parm.isMultiParmParent(): rampname = parm.name() ramp = parm.evalAsRamp() interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] keylist = [] for i,key in enumerate(ramp.keys()): rampdata = { 'posindex': i, 'pos' : key, 'value': ramp.values()[i], 'interp': interplookup.index(ramp.basis()[i])} keylist.append(rampdata) ramp = { rampname: keylist } ramps.update(ramp) # <continue> ends the for loop’s current iteration continue # Write Standard Parameters data[parm.name()] = parm.eval() # Loop Through Multiparms for mpi in mplist: mparam = hda.parm(mpi) mp_inst = { mpi: [] } num = hda.parm(mpi).evalAsInt() instances = hda.parm(mpi).multiParmInstances() for i in range(num): block_data = {} for instance in instances: if instance.name().find(str(i+1)) >=0: name = instance.name() value = instance.eval() block_data[name] = value mp_inst[mpi].append(block_data) mp.update(mp_inst) #print('........\n') # Wrapper for Standard Parameters datas = { stdgroup: data } # Wrapper for Ramp Parameters ramps = { rampgroup: ramps } # Wrapper for Multiparms mps = { mpgroup: mp } # Append Ramp Values to the Final Dictionary datas.update(ramps) # Append the Mltiparm Values to the Final Dictionary datas.update(mps) if not os.path.exists(dir): os.makedirs(dir) with open(filepath, 'w') as outfile: json.dump(datas, outfile, indent=4) print('Parameters exported to:', filepath) ### Import Parameters def read_params(kwargs): hda = kwargs['node'] params = hda.parmsInFolder(['Parameters']) from sys import platform dir = hda.parm('path').evalAsString() + '/cache/' if platform == 'darwin': dir = hda.parm('path').evalAsString() + 'cache/' filepath = dir + '_config_' + hda.parm('preset').evalAsString() + '.json' if len(filepath) > 0 and os.path.isfile(filepath): # Read JSON for Standard Parameters with open(filepath, 'r') as outfile: parameters = json.load(outfile)[stdgroup] # Read JSON for Ramp Parameters with open(filepath, 'r') as outfile: rparameters = json.load(outfile)[rampgroup] # Read JSON for Multiparms with open(filepath, 'r') as outfile: mparameters = json.load(outfile)[mpgroup] # Set Standard Parameters for parm_name, value in parameters.items(): parm = hda.parm(parm_name) if parm is not None: parm.set(value) # Set Ramp Parameters # Outer Loop Runs Over Every Ramp Parameter Name for parm_name, value in rparameters.items(): parm = hda.parm(parm_name) if parm is not None: keys = [] values = [] bases = [] interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] # Inner Loop - We Query the Current Ramp Name With <[parm_name]> for i in rparameters[parm_name]: keys.append(i['pos']) values.append(i['value']) bases.append(interplookup[i['interp']]) # Initialize New Ramp ramp = hou.Ramp(bases, keys, values) # Set Ramp Parameters parm.set(ramp) # Set Multiparms # Outer Loop Runs Over Every Multiparm Name for parm_name, value in mparameters.items(): parm = hda.parm(parm_name) parm.set(0) if len(mparameters) > 0: blocks = mparameters[parm_name] for i in range(len(blocks)): parm.insertMultiParmInstance(i) for name, value in blocks[i].items(): hda.parm(name).set(value) print('Parameters imported from:', filepath) else: hou.ui.displayMessage('Couldnt find the file!!')
- fr_3D
- Member
- 9 posts
- Joined: Nov. 2020
- Offline
Nevermind, I found a solution. Now all parameters including multiparms, float and color ramps (also inside subfolders and multiparms) can be written to and loaded from the .json file automatically. A problem with digits in Multiparm names and numbers > 10 is also fixed.
### JSON Export Script ### Usage # All Parameters within the folder <parameters> can be written to a .json file with the <Save Config> button. # They can be loaded back as a preset with the <Load Config> button. # By default the .json files are saved in a folder named <cache> within the current $HIP directory (can be changed in <Home Directory>). # There is a dropdown menu with numbered preset options. Every preset corresponds to a separate .json file. # Standard parameter types are supported including Color and Float Ramps. # Multiparms and Ramps can be nested in subfolders. ### Limitations # Multiparms cannot be nested within multiparms. # Names of multiparm attributes need to end with the number sign # # Names of multiparm attributes can contain digits, but not directly before the number sign # (e.g: float3_# works, float3# doesn't). ############## ### Global ### ############## import json, os # Groups for Separating and Wrapping Ramp, Standard and Multiparm Data in the .json File stdgroup = 'standard' rampgroup = 'ramps' mpgroup = 'multiparms' mprampgroup = 'mpramp' ######################### ### Export Parameters ### ######################### def write_params(kwargs): hda = kwargs['node'] params = hda.parmsInFolder(['Parameters']) #print('........\n', params) from sys import platform dir = hda.parm('path').evalAsString() + '/cache/' if platform == 'darwin': # Considers Windows / MacOS File Path Difference dir = hda.parm('path').evalAsString() + 'cache/' filepath = dir + '_config_' + hda.parm('preset').evalAsString() + '.json' data = {} ramp = {} ramps = {} mp = {} ### Gather Standard and Ramp Parameters ####################################### for parm in params: # Loop Through All Parameters in Folder if not parm.isHidden(): if parm.isMultiParmParent(): # First Loop Through Ramp Parameters rampname = parm.name() ramp = parm.evalAsRamp() interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] keylist = [] for i,key in enumerate(ramp.keys()): rampdata = { 'posindex': i, 'pos' : key, 'value': ramp.values()[i], 'interp': interplookup.index(ramp.basis()[i])} keylist.append(rampdata) ramp = { rampname: keylist } ramps.update(ramp) # Write Ramp Parameters with the Ramp Name as Wrapper to <ramps> # <continue> ends the for loop’s current iteration https://www.coursera.org/tutorials/python-while-loop # and skips ramp parameters when creating the data dictionary in the next step # ramps consist of multiple elements like multiparms and result in errors when not excluded from the standard evaluation continue data[parm.name()] = parm.eval() # Write Remaining Standard Parameters to <data> ### Initialize List with Names of Parameter Groups ################################################## allparm = hda.parms() # All Parameters ramplist = list(ramps.keys()) # Ramps Outside of Multiparms mplist = [] # Multiparm Folders mpramplist = [] # Ramps Inside Multiparms ### Create Lists with Names of Multiparms + Ramps Outside / Inside of Multiparms ################################################################################ for mpi in allparm: # For Every Parameter if not mpi.isHidden(): if mpi.isMultiParmParent(): # If the Parameter is a Multiparm Parent allparmname = mpi.name() # Check if the Parameter has a Parent - Returns the Parent for Ramps Inside Multiparms but None for Multiparms pmp = mpi.parentMultiParm() if not pmp == None: mpramplist.append(allparmname) if not allparmname in ramplist and pmp == None: # If the Parameter Name is not in the Ramplist and has no Parent mplist.append(allparmname) # Update mplist and Append allparmname ### Gather Multiparm Parameters ############################### for mpi in mplist: # For Every Multiparm Folder mparam = hda.parm(mpi) mp_inst = { mpi: [] } num = hda.parm(mpi).evalAsInt() # Evaluate the Number of the Multiparm Instances instances = hda.parm(mpi).multiParmInstances() # Get the Parameters Within the Multiparm Instances for i in range(num): # For Every Multiparm (Folder) block_data = {} for instance in instances: # For Every Parameter Within the Multiparm Instances # Index Calculation # #...................# instname = instance.name() revinstname = instname[::-1] # Reverse Instance Name if revinstname[0].isdigit(): # If First Character is Digit cleaninstname = revinstname.lstrip('0123456789') # Remove Digits From the Beginning (Reversed Ending) strip = len(cleaninstname) # Get Length of Pure Instance Name (Without Digits) index = instname[strip:] # Slice Index Number out of Instance Name else: # In Case of a Character Suffix (Houdini x y z Vector) cleaninstname = revinstname[1:].lstrip('0123456789') strip = len(cleaninstname) index = instname[strip:-1] # Slice Index Number out of Instance Name and Remove Vector Suffix (x y z) #...................# # For all Parameters in Multiparm except Ramps # #..............................................# if not instname in mpramplist and int(index) == i+1: # If Instance Name is not in List of Ramps (Inside Multiparms) name = instance.name() value = instance.eval() block_data[name] = value #..............................................# # For Ramps in Multiparms # #.........................# if instname in mpramplist and int(index) == i+1: mprampname = instance.name() mpramp = instance.evalAsRamp() interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] mpkeylist = [] for ir,key in enumerate(mpramp.keys()): rampdata = { 'posindex': ir, 'pos' : key, 'value': mpramp.values()[ir], 'interp': interplookup.index(mpramp.basis()[ir])} mpkeylist.append(rampdata) mpramps = { mprampname: mpkeylist } block_data.update(mpramps) # Add Ramps to Block Data #.........................# mp_inst[mpi].append(block_data) mp.update(mp_inst) datas = { stdgroup: data } # Wrapper for Standard Parameters ramps = { rampgroup: ramps } # Wrapper for Ramp Parameters mps = { mpgroup: mp } # Wrapper for Multiparms datas.update(ramps) # Append Ramp Values to the Final Dictionary datas.update(mps) # Append the Multiparm Values to the Final Dictionary if not os.path.exists(dir): os.makedirs(dir) with open(filepath, 'w') as outfile: json.dump(datas, outfile, indent=4) print('Parameters exported to:', filepath) ######################### ### Import Parameters ### ######################### def read_params(kwargs): hda = kwargs['node'] params = hda.parmsInFolder(['Parameters']) from sys import platform dir = hda.parm('path').evalAsString() + '/cache/' if platform == 'darwin': dir = hda.parm('path').evalAsString() + 'cache/' filepath = dir + '_config_' + hda.parm('preset').evalAsString() + '.json' if len(filepath) > 0 and os.path.isfile(filepath): with open(filepath, 'r') as outfile: parameters = json.load(outfile)[stdgroup] # Read JSON for Standard Parameters with open(filepath, 'r') as outfile: rparameters = json.load(outfile)[rampgroup] # Read JSON for Ramp Parameters with open(filepath, 'r') as outfile: mparameters = json.load(outfile)[mpgroup] # Read JSON for Multiparms # Set Standard Parameters # #.........................# for parm_name, value in parameters.items(): parm = hda.parm(parm_name) if parm is not None: parm.set(value) #.........................# # Set Ramp Parameters # #.....................# for parm_name, value in rparameters.items(): # Runs Over Every Ramp Parameter Name parm = hda.parm(parm_name) if parm is not None: keys = [] values = [] bases = [] interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] for i in rparameters[parm_name]: # Query Current Ramp Name With <[parm_name]> keys.append(i['pos']) values.append(i['value']) bases.append(interplookup[i['interp']]) ramp = hou.Ramp(bases, keys, values) # Initialize New Ramp parm.set(ramp) # Set Ramp Parameters #.....................# # Set Multiparms # #................# for parm_name, value in mparameters.items(): # Runs Over Every Multiparm (Folder) Name parm = hda.parm(parm_name) parm.set(0) if len(mparameters) > 0: blocks = mparameters[parm_name] # Extract all Parameters from Within Each Multiparm (Folder) as Blocks for ib in range(len(blocks)): # For Every Block Within Every Multiparm (Folder) parm.insertMultiParmInstance(ib) for name, value in blocks[ib].items(): # Test Dictionary Depth https://www.geeksforgeeks.org/python-find-depth-of-a-dictionary/ def dict_depth(dic, level = 1): str_dic = str(dic) counter = 0 for i in str_dic: if i == "{": # Curly Braces Indicate Nesting Depth counter += 1 return(counter) dic = value # Set Standard Multiparm Parameters # #...................................# if dict_depth(dic) == 0: # No Curly Braces - no Ramp hda.parm(name).set(value) #...................................# # Set Ramps in Multiparms # #.........................# else: # Min. One Curly Brace - Ramp if parm is not None: keys = [] values = [] bases = [] interplookup = [hou.rampBasis.Constant, hou.rampBasis.Linear, hou.rampBasis.CatmullRom, hou.rampBasis.MonotoneCubic, hou.rampBasis.Bezier, hou.rampBasis.BSpline, hou.rampBasis.Hermite] for im in value: # Inner Loop - We Query the Current Ramp Name With <[parm_name]> keys.append(im['pos']) values.append(im['value']) bases.append(interplookup[im['interp']]) ramp = hou.Ramp(bases, keys, values) # Initialize New Ramp hda.parm(name).set(ramp) #.........................# #................# print('Parameters imported from:', filepath) else: hou.ui.displayMessage('Couldnt find the file!!') #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
- Quick Links