• Login
sketchucation logo sketchucation
  • Login
🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

Importing Bulk Attribute Values from CSV

Scheduled Pinned Locked Moved Developers' Forum
11 Posts 3 Posters 1.8k Views 3 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    hank
    last edited by 5 Jun 2017, 04:42

    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:

    
    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!

    1 Reply Last reply Reply Quote 0
    • S Offline
      sdmitch
      last edited by 5 Jun 2017, 16:06

      Perhaps if you would share a sample model containing the dynamic component and a sample .csv file.

      Nothing is worthless, it can always be used as a bad example.

      http://sdmitch.blogspot.com/

      1 Reply Last reply Reply Quote 0
      • H Offline
        hank
        last edited by 5 Jun 2017, 16:29

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

        A basic wall dynamic component

        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...

        A list of assemblies for commercial construction

        And for convenience, here is the ruby file too!

        ruby CSV attribute importer

        1 Reply Last reply Reply Quote 0
        • T Offline
          TIG Moderator
          last edited by 5 Jun 2017, 17:45

          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...

          TIG

          1 Reply Last reply Reply Quote 0
          • H Offline
            hank
            last edited by 5 Jun 2017, 18:41

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

            1 Reply Last reply Reply Quote 0
            • T Offline
              TIG Moderator
              last edited by 6 Jun 2017, 11:45

              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 ???

              TIG

              1 Reply Last reply Reply Quote 0
              • H Offline
                hank
                last edited by 6 Jun 2017, 13:53

                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:

                screenshot

                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.

                1 Reply Last reply Reply Quote 0
                • T Offline
                  TIG Moderator
                  last edited by 6 Jun 2017, 16:34

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

                  How about this ?

                  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
                  

                  TIG

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    hank
                    last edited by 6 Jun 2017, 19:30

                    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.

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      hank
                      last edited by 9 Jun 2017, 02:55

                      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:

                      
                      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")
                      
                      
                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        hank
                        last edited by 9 Jun 2017, 03:49

                        BTW, the answer to the original question was that

                        
                        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

                        
                        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...

                        
                        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:

                        
                        set_result = Sketchup.active_model.set_attribute("dynamic_attributes", input[0], att_string.to_s )
                        
                        
                        1 Reply Last reply Reply Quote 0
                        • 1 / 1
                        1 / 1
                        • First post
                          11/11
                          Last post
                        Buy SketchPlus
                        Buy SUbD
                        Buy WrapR
                        Buy eBook
                        Buy Modelur
                        Buy Vertex Tools
                        Buy SketchCuisine
                        Buy FormFonts

                        Advertisement