Importing Bulk Attribute Values from CSV

Importing Bulk Attribute Values from CSV

Postby hank » Mon Jun 05, 2017 5:42 am

Hello All,

I have worked up the script below in an attempt to allow myself to input a large number of annoyingly long attributes from a CSV file into a Dynamic Component's attribute dictionary. Yes, yes, I read several places that this has been covered extensively and that TIG had written a few scripts to accomplish this. That was not really my experience and I had trouble finding this exact function. I used TIG's script as a starting point but the documentation on dictionaries seemed thin and not all that helpful.

I also understand that there are a number of extensions out there but I wanted to try and understand what was going on under the hood with dictionaries so I could possibly take advantage of them and hopefully help others do the same.

Here it is:
Code: Select all
require 'sketchup.rb'
def set_attribute(key_in, value_in)
   model = Sketchup.active_model
   target_dictionary = model.attribute_dictionaries['dynamic_attributes']
   new_key = target_dictionary[key_in] = value_in
   #puts key_in
end

def load_attributes()

   list = []
   $option_string = "please select an attribute"
   model = Sketchup.active_model
   attrdicts = model.attribute_dictionaries
   attrdict = attrdicts["dynamic_attributes"]
   attrdict.each{|key,value|
      #puts "key: #{key} | value: #{value}"
      $option_string += "|#{key}"
   }
   list << $option_string

   prompts = ["What attribute would you like to input values for?"]
   defaults = ["_leny_options"]
   $input = UI.inputbox(prompts, defaults, list, "Select Attribute Target")
   #puts $input

   $att_string = ""
   csv=UI.openpanel("Choose CSV File...")
   lines=IO.readlines(csv)
   lines.each{|line|
      line.chomp!
      next if line.empty?
      new_line = line.gsub(",", " ") #replace commas
      new_line = new_line.gsub("  ", "") #replace double spaces
      new_line = new_line.gsub("   ", "") #replace double spaces (again)
      new_line = new_line.gsub("& ", "&") #replace double spaces (again)
      new_line = new_line.gsub("= ", "=") #replace double spaces (again)
      $att_string += new_line.to_s
   }
   #puts $att_string
   set_attribute('_wall_thickness_options',$att_string)
   #set_attribute($input,$att_string)
end

def report_attributes()
   model = Sketchup.active_model
   attrdicts = model.attribute_dictionaries
   attrdict = attrdicts["dynamic_attributes"]
   attrdict.each{|key,value|
      puts "key: #{key} | value: #{value}"
   }
end


Now for my dilemma...

You can see that I added a drop-down prompt for a user to select a particular key that is already in the model (I'm only focusing on the 'dynamic_attributes' library though there are others). Well, the input I get from the user prompt ends up adding a key to the dictionary like so...

If I wanted to overwrite the key _lenx_options for example, it comes in as a NEW key called ["_lenx_options"] which is not in fact setting the existing key but creating a new one.

How can I pass the input argument correctly to the set_attribute def?

Thanks for any help!
0

hank 
 

Re: Importing Bulk Attribute Values from CSV

Postby sdmitch » Mon Jun 05, 2017 5:06 pm

Perhaps if you would share a sample model containing the dynamic component and a sample .csv file.
0
Nothing is worthless, it can always be used as a bad example.

http://sdmitch.blogspot.com/
User avatar
sdmitch 
PluginStore Author
PluginStore Author
 

Re: Importing Bulk Attribute Values from CSV

Postby hank » Mon Jun 05, 2017 5:29 pm

Sure! Here is a simple wall DC that I wanted to bring in a large list of wall assemblies:

WALL-COMMERCIAL.skp


and here is the list of assemblies I put together in a spreadsheet - you will see that I added the "&" separator and "=" value indicator right in the spreadsheet because I was being lazy about the string cleanup...

WALL ASSEMBLIES - COMMERCIAL-EXPORT.csv


And for convenience, here is the ruby file too!

import_attributes.rb
0

hank 
 

Re: Importing Bulk Attribute Values from CSV

Postby TIG » Mon Jun 05, 2017 6:45 pm

A few somewhat random comments...

Please enclose your Ruby code inside your own module.

Do not use 'global' variables [$xxx].
Using instance-variables [@xxx] will work within your module across its various methods...
Although as far as I can see the $xxx ones you've made are only used in one method anyway, so they are unnecessary.

The various DC attributes belong to each component's definition - not to the model - UNLESS that entire model is itself a DC...
0
TIG
User avatar
TIG 
Global Moderator
 

Re: Importing Bulk Attribute Values from CSV

Postby hank » Mon Jun 05, 2017 7:41 pm

Thanks TIG... will do. Any idea about the problem I mentioned?
0

hank 
 

Re: Importing Bulk Attribute Values from CSV

Postby TIG » Tue Jun 06, 2017 12:45 pm

The DC dictionary attached to the model reports as this:
Sketchup.active_model.attribute_dictionaries['dynamic_attributes'].each_pair{|k,v| puts "#{k} = #{v}" }

_formatversion = 1.0
_has_movetool_behaviors = 0.0
_hasbehaviors = 1.0
_lastmodified = 2017-06-04 23:49
_lengthunits = INCHES
_lenx_label = LenX
_lenx_nominal = 766.4475123076386
_leny_access = LIST
_leny_formlabel = THICKNESS
_leny_label = LenY
_leny_nominal = 6.500000000000207
_leny_options = &--------------INTERIOR--------------=0&1.500 : 0.625 GWB | 0.875 METAL FRAMING=1.500&3.125 : 0.625 GWB | 2.500 METAL FRAMING=3.125&4.250 : 0.625 GWB | 3.625 METAL FRAMING=4.250&6.625 : 0.625 GWB | 6.000 METAL FRAMING=6.625&8.625 : 0.625 GWB | 8.000 METAL FRAMING=8.625&4.875 : 0.625 GWB | 3.625 METAL FRAMING | 0.625 GWB =4.875&7.250 : 0.625 GWB | 6.000 METAL FRAMING | 0.625 GWB =7.250&9.250 : 0.625 GWB | 8.000 METAL FRAMING | 0.625 GWB =9.250&5.250 : 0.625 GWB | 3.625 METAL FRAMING | 0.500 CBB | 0.500 TILE=5.250&7.625 : 0.625 GWB | 6.000 METAL FRAMING | 0.500 CBB | 0.500 TILE=7.625&9.625 : 0.625 GWB | 8.000 METAL FRAMING | 0.500 CBB | 0.500 TILE=9.625&6.125 : 0.625 GWB | 0.625 GWB | 3.625 METAL FRAMING | 0.625 GWB | 0.625 GWB =6.125&8.500 : 0.625 GWB | 0.625 GWB | 6.000 METAL FRAMING | 0.625 GWB | 0.625 GWB =8.500&10.500 : 0.625 GWB | 0.625 GWB | 8.000 METAL FRAMING | 0.625 GWB | 0.625 GWB =10.500&7.625 : 7.625 CMU =7.625&11.625 : 11.625 CMU =11.625&8.875 : 0.625 GWB | 7.625 CMU | 0.625 GWB =8.875&12.875 : 0.625 GWB | 11.625 CMU | 0.625 GWB =12.875&--------------EXTERIOR--------------=0&5.875 : 0.625 GWB | 3.625 METAL FRAMING | 0.625 FRGWB | 1.000 FIN=5.875&8.250 : 0.625 GWB | 6.000 METAL FRAMING | 0.625 FRGWB | 1.000 FIN=8.250&10.250 : 0.625 GWB | 8.000 METAL FRAMING | 0.625 FRGWB | 1.000 FIN=10.250&6.625 : 0.625 GWB | 3.625 METAL FRAMING | 0.750 PLYWOOD | 0.625 FRGWB | 1.000 FIN =6.625&9.000 : 0.625 GWB | 6.000 METAL FRAMING | 0.750 PLYWOOD | 0.625 FRGWB | 1.000 FIN =9.000&11.000 : 0.625 GWB | 8.000 METAL FRAMING | 0.750 PLYWOOD | 0.625 FRGWB | 1.000 FIN =11.000&9.500 : 0.625 GWB | 3.625 METAL FRAMING | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =9.500&11.875 : 0.625 GWB | 6.000 METAL FRAMING | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =11.875&13.875 : 0.625 GWB | 8.000 METAL FRAMING | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =13.875&9.875 : 0.625 GWB | 7.625 CMU | 0.625 FRGWB | 1.000 FIN=9.875&13.875 : 0.625 GWB | 11.625 CMU | 0.625 FRGWB | 1.000 FIN=13.875&13.500 : 0.625 GWB | 7.625 CMU | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =13.500&17.500 : 0.625 GWB | 11.625 CMU | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =17.500&13.875 : 0.625 GWB | 8.000 CMU | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =13.875&10.250 : 0.625 GWB | 8.000 TILT WALL | 0.625 FRGWB | 1.000 FIN=10.250&10.250 : 0.625 GWB | 8.000 TILT WALL | 0.625 FRGWB | 1.000 FIN=10.250&13.875 : 0.625 GWB | 8.000 TILT WALL | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =13.875&13.875 : 0.625 GWB | 8.000 TILT WALL | 0.625 FRGWB | 1.000 AIR | 3.625 BRICK =13.875
_leny_units = DEFAULT
_lenz_access = TEXTBOX
_lenz_formlabel = WALL_HEIGHT
_lenz_label = LenZ
_lenz_nominal = 120.0
_lenz_units = DEFAULT
_name = WALL_COMMERCIAL
_scaletool_formlabel = ScaleTool
_scaletool_label = ScaleTool
_scaletool_units = STRING
lenx = 174.3749999999994
leny = 7.625
lenz = 120
scaletool = 124


I assume that you don't want this block of text associated with one 'key' ??

You need to construct your CSV in a way that gives what you want.
When you read it to make 'lines' you can iterate each 'line', using chomp! to snip off the \n carriage-return.
You can then use split at ',' to access various key/value pairs ??

At the moment I am unclear about what it is you want to end up with after running your code...
Perhaps trying a very simple version first will help ???
0
TIG
User avatar
TIG 
Global Moderator
 

Re: Importing Bulk Attribute Values from CSV

Postby hank » Tue Jun 06, 2017 2:53 pm

That key is actually EXACTLY what I want. I just had to do it by hard coding the $input argument in set_attribute($input,$att_string) to read "_leny_options" (a string) in order to get it to work. When I feed in $input from UI.inputbox it comes creates a separate new key called ["_leny_options"] with brackets and quotes around it. That is the problem - somehow I need to format $input so this does not happen.

The reason I want that key to be so long is because this is what I want the drop-down to look like:

Screen Shot 2017-06-06 at 9.52.37 AM.jpg


peripheral information...

drop-down attributes are stored in a &key1=value1&key2=value2&key3=value3... format in the dictionary

and

UI.inputbox will present a drop-down if given 4 arguments and the 3rd argument is a bar separated list.
0

hank 
 

Re: Importing Bulk Attribute Values from CSV

Postby TIG » Tue Jun 06, 2017 5:34 pm

I understand how a drop-down list is constructed for a DC.
Now I see beyond your complexity...

How about this ?

Code: Select all
def set_attribute(key_in=nil, value_in='')
  return unless key_in
  Sketchup.active_model.set_attribute("dynamic_attributes", key_in.to_s, value_in.to_s )
end
0
TIG
User avatar
TIG 
Global Moderator
 

Re: Importing Bulk Attribute Values from CSV

Postby hank » Tue Jun 06, 2017 8:30 pm

Thanks TIG. I'll give that a try.

Of course you do... that info is for anyone else reading this thread and having a similar struggle as I did.
0

hank 
 

Re: Importing Bulk Attribute Values from CSV

Postby hank » Fri Jun 09, 2017 3:55 am

Alright @TIG, I re-wrote this script trying to comply with your suggestions and it worked! Thank you for your help!

Here is the updated script for your entertainment:
Code: Select all
require 'sketchup.rb'
module AttModuleTop
   module AttModuleBottom
      class<<self
         def list_att()
            model = Sketchup.active_model
            attrdicts = model.attribute_dictionaries
            attrdict = attrdicts["dynamic_attributes"]
            if(!attrdict)
               UI.messagebox("AttTools is intended for use within Dynamic Component Files only")
            else
               @prompts = ["What attribute to overwrite"]
               @defaults = [""]
               @list = []
               @option_pairs = ""
               option_string = "select attribute to overwrite"
               attrdict.each{|key,value|
                  @option_pairs += "key: #{key} | value: #{value}\n"
                  option_string += "|#{key}"
               }
               @list << option_string
            end
         end
         def replace_att()
            list_att()
            new_prompt = "What should it be set to?"
            @prompts << new_prompt
            input = UI.inputbox(@prompts, @defaults, @list, "Select Attribute Target")
            set_result = Sketchup.active_model.set_attribute("dynamic_attributes", input[0], input[1] )
            UI.messagebox('succesfully set ' + input[0] + ' to ' + set_result + '!')
         end
         def load_att()
            list_att()
            input = UI.inputbox(@prompts, @defaults, @list, "Select Attribute Target")
            att_string = ""
            csv=UI.openpanel("Choose CSV File...")
            lines=IO.readlines(csv)
            lines.each{|line|
               line.chomp!
               next if line.empty?
               new_line = line.gsub(",", " ") #replace commas
               new_line = new_line.gsub("  ", "") #replace double spaces
               new_line = new_line.gsub("   ", "") #replace double spaces (again)
               new_line = new_line.gsub("& ", "&") #replace double spaces (again)
               new_line = new_line.gsub("= ", "=") #replace double spaces (again)
               att_string += new_line.to_s
            }
            set_result = Sketchup.active_model.set_attribute("dynamic_attributes", input[0], att_string.to_s )
            UI.messagebox('succesfully set ' + input[0] + ' to ' + set_result + '!', MB_MULTILINE)
         end
         def report_att()
            list_att()
            if(@option_pairs)
               UI.messagebox(@option_pairs, MB_MULTILINE)
               #puts @option_pairs
            end
         end
      end # end of class
   end # end of module AttModuleBottom
end # end of module AttModuleTop

# menus ##############################################################

if( not file_loaded?("att_tools.rb") )
   main_menu = UI.menu("Plugins").add_submenu("Att Tools")
   main_menu.add_item("Load Attributes") {(AttModuleTop::AttModuleBottom::load_att)}
   main_menu.add_item("Replace Attribute") {(AttModuleTop::AttModuleBottom::replace_att)}
   main_menu.add_item("Report Attributes") {(AttModuleTop::AttModuleBottom::report_att)}
end
file_loaded("att_tools.rb")
0

hank 
 

Re: Importing Bulk Attribute Values from CSV

Postby hank » Fri Jun 09, 2017 4:49 am

BTW, the answer to the original question was that

Code: Select all
input = UI.inputbox(@prompts, @defaults, @list, "Select Attribute Target")


returns an array of values because typically the inputbox would present more than 1 option. In my case there was only one input or prompt so when I put input into

Code: Select all
set_result = Sketchup.active_model.set_attribute("dynamic_attributes", input, att_string.to_s )


I was actually sending in an array and thus setting a new key in the format ["whatever user put into inputbox"]. Even .to_s did not seem to help...

Code: Select all
set_result = Sketchup.active_model.set_attribute("dynamic_attributes", input.to_s, att_string.to_s )


The answer was to get the first item in the array like so:

Code: Select all
set_result = Sketchup.active_model.set_attribute("dynamic_attributes", input[0], att_string.to_s )
0

hank 
 

SketchUcation One-Liner Adverts

by Ad Machine » 5 minutes ago



Ad Machine 
Robot
 



 

Return to Developers' Forum

Who is online

Users browsing this forum: No registered users and 2 guests

Visit our sponsors: