export visibility and attribute to excel

export visibility and attribute to excel

gbG5A5W
Enthusiast Enthusiast
6,427 Views
50 Replies
Message 1 of 51

export visibility and attribute to excel

gbG5A5W
Enthusiast
Enthusiast

I have multiple blocks (always) containing an attribute (called type) and (sometimes) a visibility (called kleur).

All blocknames start with ID-, EX-, EP- or EW-. I use these blocks to make an assembly. After assembling I need to export the number of blocks per block, the attribute and the visibility to excel. To accomplish that I use the data extraction tool:

gbG5A5W_0-1729866848196.png

It's a lot of clicks for everytime the same settings. Is it possible to do this faster?

0 Likes
Accepted solutions (2)
6,428 Views
50 Replies
Replies (50)
Message 2 of 51

ВeekeeCZ
Consultant
Consultant

This should do the trick

 

 

eekeeCZ_0-1729872602856.png

 

0 Likes
Message 3 of 51

Rick_Tolleshaug_TSC
Advocate
Advocate

I see BeekeeCZ has already posted a possible solution. If theirs works...great, otherwise here is another option.

 

Using a slightly different approach, ExportAV.lsp retrieves its data from the drawing's database instead of getting a selection set of the drawing.  Both work fine.  The database approach takes more code but I was well into it and thought I'd present an alternative.

 

ExportAV.lsp collects data based on these specifics (as I understood it):

1.  Only search out blocks whose effective name matches pattern "ID-*,EX-*,EP-*,EW-*"

2.  Retrieve value of each block's Attribute whose tag is "TYPE"

3.  Retrieve value of each block's dynamic block Visibility parameter named "kleur" (if applicable)

4.  Determine Quantity of each unique block configuration

5.  Compile data and write to CSV file

 

Currently ExportAV.lsp includes one additional column "Block Name" but this can be easily removed by opening LSP file in text editor and editing the two lines with comment ";<-EDIT...".

 

Use APPLOAD to load "ExportAV.lsp" (command: "ExportAV")

0 Likes
Message 4 of 51

Sea-Haven
Mentor
Mentor

"5.  Compile data and write to CSV file" why not just open a excel and write direct, cut out the write csv step ? Posted Alan excel.lsp many times has the defuns required.

0 Likes
Message 5 of 51

gbG5A5W
Enthusiast
Enthusiast

Thank you guys so much putting this effort in to help me out on this.

 

@Rick_Tolleshaug_TSC: I tested the lisp. All have an attribute an 8 of them have a visibility state. And there are some blocks with nested blocks (sorry, should haven mentioned that...). I also exported using the DATA-extraction tool. I attached the compare, first 4 columns are lisp, next 4 columns are data extraction. For a better understanding:

- ID-100-091 to ID-100-261 are nested in a block called wand. The block holds 2 of each, (ID-100-261 is added in the drawing three times). So the numbers are a bit weird, especially the 8 times ID-100-255, which is only twice in the block (checked it to be sure I didn't make a mistake)

- ID-400-300 to ID-400-462 are blocks with to visibility states for colour (kleur, zwart and wit)

 

@ВeekeeCZ: I have to type the code, so it will take a while. Is it possible to share the code as text?

 

And I agree with @Sea-Haven: converting from csv to columns would be an extra step in the excel-file. If it could be columns right away that would be welcome.

 

In addition: is it possible to write the export directly in the first tab of a template called Xdwgpos?

 

Many thanks again!

0 Likes
Message 6 of 51

Sea-Haven
Mentor
Mentor

Need a dwg then will have a think about it yes do have make a count of blocks and make a table into dwg 1st, then have "send table to excel". That may be a better way to do task.

0 Likes
Message 7 of 51

daniel_cadext
Advisor
Advisor

Looks like a job for Python, Pandas and ExcelWriter, This should get nested blocks

import traceback
from pyrx_imp import Ap, Db, Ed, Ge, Gi, Gs, Rx
import pandas as pd


def PyRxCmd_doit():
    try:
        propname = "Visibility1"
        namefilter = ("ID-", "EX-", "EP-", "EW-", "Limit")
        blockmap = {"Name": [], "State": [], "QTY": []}

        db = Db.curDb()
        bt = Db.BlockTable(db.blockTableId())
        for btrid in bt.toDict().values():
            btr = Db.DynBlockTableRecord(btrid)
            if not btr.isDynamicBlock():
                continue

            refids = []
            for anon in [Db.BlockTableRecord(id) for id in btr.getAnonymousBlockIds()]:
                refids.extend(anon.getBlockReferenceIds())

            for ref in [Db.BlockReference(id) for id in refids]:
                name = ref.getBlockName()
                if not name.startswith(namefilter):
                    continue
                
                dynref = Db.DynBlockReference(ref.objectId())
                props = dynref.getBlockProperties()
                
                for prop in props:
                    if not prop.propertyName() == propname:
                        continue
                    blockmap["Name"].append(name)
                    blockmap["State"].append(prop.value().getString())
                    blockmap["QTY"].append(1)

            df = pd.DataFrame(blockmap)
            gdf = df.groupby(["Name", "State"], sort=False, as_index=False).agg(
                {"QTY": "sum"}
            )

            with pd.ExcelWriter("e:\\pandas_to_excel.xlsx") as writer:
                gdf.to_excel(writer, sheet_name="sheet1", index=False)

    except Exception as err:
        traceback.print_exception(err)

 

blk.png

 

xlsx.png

Python for AutoCAD, Python wrappers for ARX https://github.com/CEXT-Dan/PyRx
0 Likes
Message 8 of 51

gbG5A5W
Enthusiast
Enthusiast

Again, many thanks for this!

 

@Sea-Haven: I've attached a sample dwg, containing a series of blocks.

 

@daniel_cadext: I need some help on this one. In LISP I know the filename has to be the name after defun. I think that this code is not lisp. I tried to save and load it as LISP (filename PyRxCmd_doit), but that doesn't do the trick.

I found that I need a add-on PyRx.arx, but there it ended for my knowledge.

How do I work with this?

0 Likes
Message 9 of 51

Rick_Tolleshaug_TSC
Advocate
Advocate

Being my codependent self, attached is typed-up LISP file of ExportAtts.lsp written by @ВeekeeCZ.

It required fixing three small typos, which I went ahead and fixed - file includes comments where these changes were made.

0 Likes
Message 10 of 51

Rick_Tolleshaug_TSC
Advocate
Advocate

I looked at your compare file and can see there is more data to compile.  But just to be up front, I'm going to wait and see if others (who have been active on this thread) are going to be taking it from here to the finish line.  Others are completely welcome to use any part of my ExportAV.lsp as they see necessary.

 

Best of luck.  I will monitor to see how things develop.  Reach out to me if I can be of further help. 

0 Likes
Message 11 of 51

daniel_cadext
Advisor
Advisor

instead of using the data extraction tool, you’d be better off using the COUNTLIST command. From there you can create a table and export that

 

Python for AutoCAD, Python wrappers for ARX https://github.com/CEXT-Dan/PyRx
0 Likes
Message 12 of 51

Sea-Haven
Mentor
Mentor

Export a table to excel. The multi toggles is used to tick on/off Title, header & data.

 

0 Likes
Message 13 of 51

gbG5A5W
Enthusiast
Enthusiast

@Rick_Tolleshaug_TSC: the adapted code now results in 3 lines:

16,,RAL 9005 zwart

16,,RAL 9010 wit

65,,

 

That's not quit what I expected

 

@daniel_cadext: I tried this one, combined with the table2excel-LISP of @Sea-Haven. But now I (still) have to select the blocks manually. Besides that, I'm not getting the visibility states and the attribute I need.

 

Just because it can I used AI, to see how far it gets. I asked for exporting blocks with blockname starting with ID, EX, EP, EW, exporting count, vis state and attribute, sending it to an excelsheet DWGexport.xls, saving the file with the dwg-name in the same directory as the drawing. It comes up with this code:

 

(defun ExportBlocksToExcel ()
(vl-load-com) ; Laad de VLISP COM functies

;; Excel starten en sjabloonpad instellen
(setq excel-app (vlax-get-or-create-object "Excel.Application"))
(setq template-path "T:\\ACAD2008\\BIB\\Excel\\DWGexport.xls") ; Gebruik .xls versie

;; Controleer of het bestand beschikbaar is
(if (not (findfile template-path))
(progn
(alert (strcat "Excel sjabloon niet gevonden op de opgegeven locatie: " template-path))
(exit)
)
)

;; Probeer het Excel-bestand te openen
(setq workbook (vl-catch-all-apply 'vlax-invoke-method (list (vlax-get excel-app 'Workbooks) 'Open template-path)))
(if (vl-catch-all-error-p workbook)
(progn
(alert (strcat "Kan sjabloon niet openen. Controleer bestandstoegang of extensie: " template-path))
(exit)
)
)

;; Selecteer het eerste tabblad
(setq sheet (vlax-invoke-method workbook 'Sheets 'Item 1))

;; Haal de tekening op
(setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq dwg-path (vla-get-FullName doc))
(setq dwg-name (vl-filename-base dwg-path))

;; Doorloop alle blocks en verzamel informatie
(setq blocks (vla-get-Blocks doc))
(setq row 2) ; Begin op rij 2

(vlax-for block blocks
(setq block-name (strcase (vla-get-Name block)))
;; Filter op bloknaam
(if (or (wcmatch block-name "ID*")
(wcmatch block-name "EX*")
(wcmatch block-name "EP*")
(wcmatch block-name "EW*"))
(progn
(setq count 0 visibility "N/A" attribute "")

;; Doorloop blockreferenties en haal attributen op
(vlax-for entity block
(if (eq (vla-get-ObjectName entity) "AcDbBlockReference")
(progn
(setq count (1+ count))

;; Controleer op visibility, zet om naar string
(if (vlax-property-available-p entity 'EffectiveName)
(setq visibility (vl-princ-to-string (vla-get-EffectiveName entity))))

;; Attributen samenvoegen als string
(vlax-for att (vla-get-Attributes entity)
(setq attribute (strcat attribute (vl-princ-to-string (vla-get-TextString att)) " "))
)
)
)
)

;; Zet elke waarde om naar een string vóór het schrijven naar Excel
;; Schrijf Blocknaam
(vl-catch-all-apply (function (lambda ()
(vlax-put (vlax-invoke-method sheet 'Cells row 1) 'Value (vl-princ-to-string block-name))
)))

;; Schrijf Aantal (als string)
(vl-catch-all-apply (function (lambda ()
(vlax-put (vlax-invoke-method sheet 'Cells row 2) 'Value (itoa count))
)))

;; Schrijf Visibility (als string)
(vl-catch-all-apply (function (lambda ()
(vlax-put (vlax-invoke-method sheet 'Cells row 3) 'Value visibility)
)))

;; Schrijf Attributen (als string)
(vl-catch-all-apply (function (lambda ()
(vlax-put (vlax-invoke-method sheet 'Cells row 4) 'Value attribute)
)))

;; Ga naar de volgende rij
(setq row (1+ row))
)
)
)

;; Opslaan in .xls-formaat
(setq save-path (strcat (vl-filename-directory dwg-path) "\\" dwg-name ".xls"))
(if (vl-catch-all-error-p
(vl-catch-all-apply 'vlax-invoke-method (list workbook 'SaveAs save-path :vlax-false 56))) ; Type 56 voor .xls-bestand
(alert "Fout bij het opslaan van het Excel-bestand.")
)

;; Excel zichtbaar maken en opruimen
(vlax-put excel-app 'Visible :vlax-true)
(vlax-release-object sheet)
(vlax-release-object workbook)
(vlax-release-object excel-app)
(princ "Export voltooid en opgeslagen.")
)

(ExportBlocksToExcel)
(princ)

 

On this, it opens the correct excel-sheet, but ends with: ; error: ActiveX Server returned an error: Type mismatch

0 Likes
Message 14 of 51

Rick_Tolleshaug_TSC
Advocate
Advocate

The 3 line result is from ExportAtts.lsp which is NOT my code, @BeekeeCZ wrote that, I just typed it up for you.

ExportAV.lsp is my code and it results in 4 columns, 31 rows (see below):

Rick_Tolleshaug_TSC_0-1730566268937.png

The reason "TYPE" Attributes are missing is because nearly all blocks have their Attribute Definition with the property "Constant" enabled, which (to my knowledge) doesn't allow its value to be retrieved outside the block. You have to instead retrieve the value by examining each and every entity within the Block Definition until you find the Attribute Definition entity. It's not difficult, it's just that my code doesn't currently do this. Also, your blocks have a variety of names for their dynamic block Visibility Parameter, you specified "kleur" so that is all that is being searched. Any Visibility not named "kleur" is ignored. I saw one or more blocks with a Visibility parameters named "Type" (not an attribute but a visibility parameter), I don't know if you expected the state of these visibility parameters named "Type" to be entered under "Type" column, but my code is not currently doing this either.

 

Again, I want to be upfront, we could get my ExportAV.lsp to correctly compile the data but I'm assuming someone else is pulling this all together for you, am I correct?

0 Likes
Message 15 of 51

gbG5A5W
Enthusiast
Enthusiast

@Rick_Tolleshaug_TSC: You are completely right. I wasn't aware that a constant, invisible attribute needed an other approach exporting it. And yes,  I need both visibility states (kleur and type) to be exported. If Type (visibility parameter) comes in another column then Type (attribute) that's no problem. If it can be one column that would be better.

 

It could be that not all blocks are defined correctly, but they all should have either a visibility parameter called type or kleur, an attribute (constant, invisible) called type, or a visibility parameter kleur and an attribute (constant, invisible) called type.

 

Probably due to my incomplete information (really sorry for that) and your effort digging in the exportAV.lsp is closest to the solution. I would really appreciate it if you could alter your code.

0 Likes
Message 16 of 51

Rick_Tolleshaug_TSC
Advocate
Advocate
Thanks. I will make updates and repost ExportAV.lsp next day or two.
0 Likes
Message 17 of 51

komondormrex
Mentor
Mentor

check this one. 'get_att_vs' command gets and outputs to the console each counted block in selection set as an associated list of its name, 'type' tagged attribute value if appropriable, visibility 'kleur' state if  appropriable and total similar block quantity.

(defun parse_list (_list / unique_list is_member)
	(foreach _member _list (if (not (member _member unique_list))
									(setq unique_list (append unique_list (list _member)))
						   )
	)
	(setq unique_list (mapcar '(lambda (_member) (cons _member 0)) unique_list))
	(foreach _member _list
		(if (setq is_member (assoc _member unique_list))
				(setq unique_list (subst (cons (car is_member) (1+ (cdr is_member))) is_member unique_list))
		)
	)
)
(defun get_att (insert tag_str / att_found)
  (if (vl-some '(lambda (att) (= tag_str (vla-get-tagstring (setq att_found att))))
	    	(append (vlax-invoke insert 'getattributes) (vlax-invoke insert 'getconstantattributes))
      )
      (list (cons tag_str (vla-get-textstring att_found)))
  )
)
(defun get_vs_state (insert vs_str / dyn_prop_found)
  (if (vl-some '(lambda (dyn_prop) (= vs_str (vla-get-propertyname (setq dyn_prop_found dyn_prop))))
	    	(vlax-invoke insert 'getdynamicblockproperties)
      )
      (list (cons vs_str (vlax-get dyn_prop_found 'value)))
  )
)
(defun c:get_att_vs (/ insert_sset)
  (if (setq insert_sset (ssget '((0 . "insert"))))
    (foreach insert
	    (parse_list (vl-sort (vl-remove nil
				            (mapcar '(lambda (insert) (append (list (vla-get-effectivename insert)) (get_att insert "TYPE") (get_vs_state insert "kleur"))) 
						     (vl-remove-if-not '(lambda (insert) (wcmatch (vla-get-effectivename insert) "ID-*,EX-*,EP-*,EW-*"))
						  			(mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex insert_sset))))
					   	     )
				            )
			       	 )
		      		'(lambda (insert_1 insert_2) (< (car insert_1) (car insert_2)))
			)
	    )
      	    (print insert)
    )
  )
  (princ)
)

Command: GET_ATT_VS

Select objects: Specify opposite corner: 106 found

Select objects:

(("EX-600-BS600") . 2)
(("EX-PLINT") . 2)
(("EX-VA-567") . 2)
(("EX-WKOL") . 2)
(("EX-WKOOF") . 2)
(("ID-100-261 SW2610" ("TYPE" . "ID-100-261 systeemstaander wand 2610 mm RAL 9005")) . 3)
(("ID-300-100 perfohoek") . 10)
(("ID-300-300 PH-K" ("TYPE" . "ID-300-300 gekropte plinthouder")) . 6)
(("ID-300-600 TV1000") . 6)
(("ID-300-625 TV625" ("TYPE" . "ID-300-600 tussenverbinder hartmaat 1000 mm")) . 6)
(("ID-400-300 PAN1000300" ("TYPE" . "stroken wandpaneel 1000x300 mm") ("kleur" . "RAL 9005 zwart")) . 7)
(("ID-400-300 PAN1000300" ("TYPE" . "stroken wandpaneel 1000x300 mm") ("kleur" . "RAL 9010 wit")) . 7)
(("ID-400-362 PAN625300" ("TYPE" . "stroken wandpaneel 625x300 mm") ("kleur" . "RAL 9005 zwart")) . 7)
(("ID-400-362 PAN625300" ("TYPE" . "stroken wandpaneel 625x300 mm") ("kleur" . "RAL 9010 wit")) . 7)
(("ID-400-400 PAN1000400" ("TYPE" . "stroken wandpaneel 1000x400 mm") ("kleur" . "RAL 9005 zwart")) . 1)
(("ID-400-400 PAN1000400" ("TYPE" . "stroken wandpaneel 1000x400 mm") ("kleur" . "RAL 9010 wit")) . 1)
(("ID-400-462 PAN625400" ("TYPE" . "stroken wandpaneel 625x400 mm") ("kleur" . "RAL 9005 zwart")) . 1)
(("ID-400-462 PAN625400" ("TYPE" . "stroken wandpaneel 625x400 mm") ("kleur" . "RAL 9010 wit")) . 1)
(("ID-600-310 SD300" ("TYPE" . "ID-600-310 opiggende schapdrager L300/L270 RAL 9005")) . 8)
(("ID-600-410 SD400" ("TYPE" . "ID-600-410 opiggende schapdrager L400/L370 RAL 9005")) . 8)
(("ID-600-510 SD500" ("TYPE" . "ID-600-510 opiggende schapdrager L500/L470 RAL 9005")) . 8)

 

0 Likes
Message 18 of 51

daniel_cadext
Advisor
Advisor

Not sure if these should be included.

blks.png

Python for AutoCAD, Python wrappers for ARX https://github.com/CEXT-Dan/PyRx
0 Likes
Message 19 of 51

komondormrex
Mentor
Mentor

you mean those are nested? 

0 Likes
Message 20 of 51

daniel_cadext
Advisor
Advisor

yeah, i think so.

and from post# 5 "And there are some blocks with nested blocks (sorry, should haven mentioned that...)"

I also missed that when I penned the python routine. might as well use COUNTLIST

Python for AutoCAD, Python wrappers for ARX https://github.com/CEXT-Dan/PyRx
0 Likes