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

      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
      • sdmitchS Offline
        sdmitch
        last edited by

        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

          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
          • TIGT Online
            TIG Moderator
            last edited by

            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

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

              1 Reply Last reply Reply Quote 0
              • TIGT Online
                TIG Moderator
                last edited by

                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

                  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
                  • TIGT Online
                    TIG Moderator
                    last edited by

                    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

                      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

                        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

                          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
                          • First post
                            Last post
                          Buy SketchPlus
                          Buy SUbD
                          Buy WrapR
                          Buy eBook
                          Buy Modelur
                          Buy Vertex Tools
                          Buy SketchCuisine
                          Buy FormFonts

                          Advertisement