GhPython - partition list problem

Hi,

I’m writing a python 2 script that is designed to expand the index range of an input list based on a specific mode, then select corresponding elements using these expanded indices to generate a new data structure.
expand_list.gh (12.7 KB)

Index Expansion (expand_indices function)

  • Computes new index ranges based on the mode (Trailing, Centered, Leading).
  • Uses count to control how many neighboring elements are selected for each index.
  • Ensures index values do not exceed the input list boundaries and supports wrap-around indexing.

I am currently encountering an issue where the output from trees.PartitionList does not correctly partition the data.

As shown in the uploaded image, the current partitioning result is incorrect, while the right-side panel represents the desired partitioning outcome, which maintains the correct hierarchical relationship with the input list.

Any assistance would be greatly appreciated.

import ghpythonlib.treehelpers as th
import ghpythonlib.components as ghc

def expand_indices(index, count, mode, max_length):
""" Expand index range based on the selected mode and ensure it does not exceed the boundary """
offset = (count - 1) // 2 if mode == 0 else 0  # Centered offset

if mode == -1:  # Trailing (select previous elements)
    expanded = [index - i for i in range(count - 1, -1, -1)]
elif mode == 0:  # Centered (select both previous and next elements)
    expanded = [index + i - offset for i in range(count)]
elif mode == 1:  # Leading (select next elements)
    expanded = [index + i for i in range(count)]
else:
    raise ValueError("Invalid mode. Use -1 (Trailing), 0 (Centered), or 1 (Leading).")

# Ensure index does not exceed range
expanded = [i % max_length for i in expanded]
return expanded

# Ensure list_input is a standard list
if not isinstance(list_input, list):
raise ValueError("Input data must be a Python list.")

# Ensure list_input is a nested structure (prevent single lists from being treated as one   large list)
if not any(isinstance(sublist, list) for sublist in list_input):
list_input = [list_input]  # Convert to [[]] structure to maintain correct grouping

# Initialize output list
output_list = []

# Process each branch in list_input
for branch in list_input:
list_length = len(branch)
index_list = range(list_length)

# Expand indices
expanded_indices = [expand_indices(i, count, mode, list_length) for i in index_list]

# Select data
selected_data = [[branch[i] for i in indices] for indices in expanded_indices]

# Maintain separate branches to avoid merging data
output_list.append(selected_data)

# Flatten the data while maintaining {X;Y} structure
flat_selected_data = [item for branch in output_list for subset in branch for item in subset]

# Output the expanded list
list_ex = ghc.trees.PartitionList(flat_selected_data,count)

print selected_data

I’m a python noob, so take this with a pinch of salt… I’d take advantage of list slicing by first preparing the list depending on the offset value (which is mode combined with count) then just sliding that list one position by one and saving just the first c (c=count) items

expand_list_inno_pynoob.gh (11.5 KB)

a note: I have set the number slider to Odd numbers only, because if the “Centered” option is selected, you need to generate an equal number of right and left neighbors (which is always an even quantity), plus your central item (which always results in an odd number)

like: left_neighbors + item + right_neighbors = odd amount of total items

I guess you can avoid forcing odd numbers by using something like math.ceil when calculating the offset, but didn’t really think too much about that

2 Likes

Thanks @inno,
in fact I’m the real python noob, your script works perfectly!

Hi @inno

Thanks for your help previously.
The script worked fine until recently.

As shown in the images below,
if the input for start gets simplified, the output becomes strange.
May I ask how I can fix this?"

from ghpythonlib import treehelpers as th

start = th.tree_to_list(start)
result = []

#calculate offset value depending on mode and count
offset = int( (count-1) * mode )

for i in range(len(start)):
    container = []
    
    # prepare the list by initially shifting it by offset value
    shifted_list = start[i][offset:] + start[i][:offset]
    
    for j in range(len(shifted_list)):
        # copysave first c=count values into a separate list
        container.append(shifted_list[:count])
        
        # prepare list for next iteration by shifting it 1 position
        shifted_list = shifted_list[1:] + shifted_list[:1]
    
    result.append(container)

result = th.list_to_tree(result)

easiest solution: do not simplify it beforehand but simplify it afterwards

otherwise, with minimal code intervention, add a None here in line 3 (but I would not advice for this)

Hmm, I see your point, and I guess it’s related to how ‘tree access’ and ‘treehelpers’ work?
I’m just thinking it might be more versatile if it could accept different data paths instead of just {0;?} (for example, simplified paths or paths with a prepended/appended index).

consider that appending/prepending the same value + simplifying afterwards = appending/prepending nothing :slight_smile:

but I see why you might want to do that
keep in mind that the Python script will process a single level of branching: if you have more complex data structure and want to use that python script “as it is”, you might want to go through a Renumber Paths for instance:

expand_list_inno_pynoob_2.gh (20.7 KB)

generally speaking, consider that gh components do not care about path address, branches are just paired 1:1 “horizontally”

so these two data trees, one with renumbered path and the other with original output tree will just produce the very same when used in standard gh definitions, because they contain the same amount of items, same amount of branches, the only thing that changes are path address: