Scripting – Shuffling a collection to randomly select by percentage


randompercentageVia a tech-artists.org tweet, I came across some MAXScript for randomly selecting a specified percentage of mesh elements (for example, give me a random selection that includes 35% of all vertices).

I converted it to Python in Softimage. Note that I don’t really shuffle a collection: you can’t set items in a collection, so there’s no way to swap items. Instead, I put the collection in a list and shuffle the list.

Shuffling actually makes this harder than it has to be. Check out Alan’s nice script for a better way to do this.

si = Application
log = si.LogMessage
sisel = si.Selection
#http://creativescratchpad.blogspot.ca/2011/06/select-random-elements-by-percentage.html

import random

#
# Return a list that includes a randomly selected
# percentage of the items in a collection
#
def get_random_percentage( collection, percentage ):
	v = [x for x in collection]

	# random shuffle
	for i in range( len(v) ):
		j = random.randint( i, len(v)-1 )
		v[i], v[j] = v[j], v[i]

	# select by percentage
	step = 100/percentage
	w = []
	for i in xrange( 0, len(v), step ):
		w.append( v[i] )

#	print len(w)
#	print (percentage/100.0) * len(v)
	
	return w


Application.SelectObj("torus", "", True)
# Select a random 50% of the vertices
x = get_random_percentage( sisel(0).ActivePrimitive.Geometry.Vertices, 50 )
si.SelectObj(x)

print sisel(0).SubComponent.ComponentCollection.Count

# Suppose you had 2000 cubes.
# Select a random 25% of those 2000...
Application.SelectObj("cube*", "", True)
x = get_random_percentage( sisel, 25 )
si.SelectObj(x)

I learned a couple of things about MAXScript:

  • MAXScript arrays are 1-based
  • In the MaxScript docs, there aren’t any function/method reference pages. You have to go to a “value” page (eg Number Values) and there you’ll find all the methods. That’s fine once you know, but it was confusing at first when I didn’t see anything in the TOC for Functions or Methods.

4 thoughts on “Scripting – Shuffling a collection to randomly select by percentage

  1. Pingback: Saturday snippet – Tuple assignment | eX-SI

  2. With all due respect, you are going a very convoluted route with all this. You can do:

    def get_random_percentage(iterable, percentage):
    amount = int( float(len(iterable)) * (percentage/100.0) )
    return random.sample(iterable, amount)

    Check out my neat version of your example here:


    from win32com.client import constants as c
    import random
    xsi = Application
    XSIDialog = XSIFactory.CreateObject("XSIDial.XSIDialog")
    def get_random_percentage(iterable, percentage):
    amount = int( float(len(iterable)) * (percentage/100.0) )
    return random.sample(iterable, amount)
    def selectRandomComponents(coll, percentage, cmpType = 'ask'):
    allComponents = {
    'edges':[x for obj in coll for x in obj.ActivePrimitive.Geometry.Edges],
    'points':[x for obj in coll for x in obj.ActivePrimitive.Geometry.Points],
    'faces':[x for obj in coll for x in obj.ActivePrimitive.Geometry.Facets]
    }
    cmpTypes = allComponents.keys()
    if cmpType == 'ask':
    cmpType = cmpTypes[ XSIDialog.ComboEx('Component type?',cmpTypes,2) ]
    sample = get_random_percentage(allComponents[cmpType], percentage)
    xsi.SelectObj(sample)
    def selectRandomObjects(coll, percentage):
    sample = get_random_percentage(coll, percentage)
    xsi.SelectObj(sample)
    def main():
    selectComponents = (
    XSIUIToolkit.Msgbox(
    "Select components?\n\nYES = components\nNO = objects",
    c.siMsgYesNo+c.siMsgQuestion,
    "Random Selector" ) == c.siMsgYes
    )
    percentage = float(xsi.XSIInputBox(
    "What percentage to select?",
    "Selection percentage?",
    50 # default %
    ))
    if selectComponents:
    selectRandomComponents(xsi.Selection, percentage)
    else:
    selectRandomObjects(xsi.Selection, percentage)
    main()

    • Yes, now that I look at it, my literal conversion of that Maxscript isn’t pretty. I remember I was more focused on figuring out what that Maxscript actually did.

      No offense, but “with all due respect” always makes me think something like this 😉

      • haha, well I didn’t really mean it that way. 😉 keep up the great blog! I read it every week.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s