Python 3 controlling a Number Slider

Hello fellow designers and coders,

I am new to python especially the 3.0 implemented within grasshopper within Rhino 8.0

Very curious about the possibility to have a python component read a slider either current, min and max values and then generate steps based on a Component ie float names Frames that can push the slider from its min to max value by a function such as steps = (Max-min)/Frames

I think it’s clear I am working on a animation component and am having come issues with this last part.

This is what I have thus far:

from decimal import Decimal, getcontext

import Grasshopper as gh

from Grasshopper.Kernel.Special import GH_Group, GH_NumberSlider

import System

# Set decimal precision

getcontext().prec = 28

def safe_decimal(val):

"""Convert ANY numeric type to Python Decimal"""

if val is None:

    return Decimal('0')

try:

    if hasattr(val, 'ToString'):  # .NET object

        return Decimal(str(val))

    return Decimal(str(val))

except:

    return Decimal('0')

def safe_int(val):

"""Convert ANY numeric type to int"""

if val is None:

    return 0

try:

    if hasattr(val, 'ToString'):

        return int(float(str(val)))

    return int(float(val))

except:

    return 0

def to_net_decimal(val):

"""Convert Python Decimal to System.Decimal for Grasshopper outputs"""

if val is None:

    return System.Decimal(0)

try:

    return System.Decimal(float(val))

except:

    return System.Decimal(0)

# Convert inputs

Frames = safe_decimal(Frames) if ‘Frames’ in locals() else Decimal(‘50’)

i = safe_int(i) if ‘i’ in locals() else 0

group_name = str(group_name) if ‘group_name’ in locals() else “Animate”

doc = ghenv.Component.OnPingDocument()

found_slider = None

min_val = max_val = step = None

current_val = None

slider_name = None

frame_idx = 0

if doc:

for obj in doc.Objects:

    if isinstance(obj, GH_Group) and str(obj.NickName) == group_name:

        for comp in obj.Objects():

            if isinstance(comp, GH_NumberSlider):

                found_slider = comp

                break

    if found_slider:

        break

if found_slider and Frames > 0:

\# Read slider bounds

min_val = safe_decimal(found_slider.Slider.Minimum)

max_val = safe_decimal(found_slider.Slider.Maximum)



\# Compute step

if Frames > Decimal('1'):

    step = (max_val - min_val) / (Frames - Decimal('1'))

else:

    step = Decimal('0')



\# Clamp frame index

max_frame = min(safe_int(Frames), 999999)

frame_idx = max(0, min(safe_int(i), max_frame - 1))



\# Compute target value

target_val = min_val + (step \* Decimal(frame_idx))



\# Set slider value (must be float for .NET)

found_slider.Slider.Value = float(target_val)

found_slider.ExpireSolution(True)



current_val = target_val

slider_name = str(found_slider.NickName)

# CRITICAL FIX: Convert ALL outputs to System.Decimal

a_min = to_net_decimal(min_val)

a_max = to_net_decimal(max_val)

a_step = to_net_decimal(step)

a_val = to_net_decimal(current_val)

a_idx = frame_idx # This is already int, safe

slider_name = slider_name if slider_name else “”

Current issue:

Traceback (most recent call last):
File “rhinocode:///grasshopper/1/58edebc1-834a-4506-b38e-b45c3c5b0e5e/bbac34bc-7726-4a2f-85f8-aabeac8647f1”, line 81, in
TypeError: ‘float’ value cannot be converted to System.Decimal

I would be glad to share the final animation code as I believe it would benefit the entire community!

Best regards and thanks for your contribution,

Andres

PS this was a second attempt but it didn’t work - for same reason.

“”"

GHPython (Python 3) - Slider Animator

Rhino 8.0 compatible - uses proper .NET interop patterns

Based on McNeel Discourse best practices

“”"

import Grasshopper as gh

from Grasshopper.Kernel.Special import GH_Group, GH_NumberSlider

import System

def safe_float(val, default=0.0):

"""Convert any numeric type to float safely"""

if val is None:

    return default

try:

    \# Handle .NET types

    if hasattr(val, 'ToString'):

        return float(str(val))

    return float(val)

except:

    return default

def safe_int(val, default=0):

"""Convert any numeric type to int safely"""

if val is None:

    return default

try:

    if hasattr(val, 'ToString'):

        return int(float(str(val)))

    return int(float(val))

except:

    return default

# ========== INPUT HANDLING ==========

frames_count = safe_int(Frames, 50)

frame_index = safe_int(i, 0)

group_name = str(group_name) if ‘group_name’ in locals() else “Animate”

# ========== INITIALIZE OUTPUTS ==========

a_min = None

a_max = None

a_step = None

a_val = None

a_idx = 0

slider_name = “”

# ========== FIND SLIDER IN GROUP ==========

doc = ghenv.Component.OnPingDocument()

found_slider = None

if doc:

for obj in doc.Objects:

    if isinstance(obj, GH_Group) and str(obj.NickName) == group_name:

        for comp in obj.Objects():

            if isinstance(comp, GH_NumberSlider):

                found_slider = comp

                break

    if found_slider:

        break

# ========== COMPUTE AND SET VALUE ==========

if found_slider and frames_count > 0:

\# Get slider properties as floats (native Python)

slider_min = safe_float(found_slider.Slider.Minimum)

slider_max = safe_float(found_slider.Slider.Maximum)

slider_name = str(found_slider.NickName)



\# Compute step size

if frames_count > 1:

    step_size = (slider_max - slider_min) / float(frames_count - 1)

else:

    step_size = 0.0



\# Clamp frame index

clamped_index = max(0, min(frame_index, frames_count - 1))



\# Compute target value (pure float arithmetic)

target_value = slider_min + (step_size \* float(clamped_index))



\# KEY FIX: Set value as double (float in Python)

\# Grasshopper's Slider.Value property expects double, not Decimal

found_slider.Slider.Value = target_value



\# Expire the slider to trigger recalculation

found_slider.ExpireSolution(True)



\# Set outputs (keep as float - Grasshopper handles conversion)

a_min = slider_min

a_max = slider_max

a_step = step_size

a_val = target_value

a_idx = clamped_index

# If slider not found, outputs remain None/0/“”