Scripting Excel troubles... references in particular.

Hi all,

I have this AppleScript (below). It basically takes values from some “.ocw” files from Finder, then puts those values into Excel. I also want Excel to create graphs from each “column pair” after it has inputted them (see below for the graph chunk). The whole script works (though feel free to suggest refinements - I get the feeling it’s not very elegant :frowning: ) apart from the fact I can’t specify a reference for the series for the graph!

As I see it, the problem with the reference lies with the fact that Excel wants the range relatively (“A1:B6”) or absolutely (“$A$1:$B$6”), however I need to specify the range algebraically (i.e the column with a number not a letter) in order for the script to continue ad nauseum. Unfortunately, when I try something like:

tell application "Microsoft Excel"
	tell active sheet
		set theRange to range {column 1, cell 1}
	end tell
end tell

OR

tell application "Microsoft Excel"
	tell active sheet
		set theRange to {column 1, cell 1}
		set theRange2 to {column 2, cell 6}
		set the actualRange to (theRange & ":" & theRange2)
	end tell
end tell

It doesn’t work. Please tell me where I’m going wrong. It’s been driving me crazy. I just can’t figure out how to do it. Also, please note, I must be able to reference the range algebraically! By the way, I’m using Excel 2008.

Thanks guys! :smiley:

Also, in case you want/need them, here’s a shortened sample of the files I’m using: http://kttns.org/vlowf

[b]The Script[/b]

set AppleScript's text item delimiters to ""
set tid to AppleScript's text item delimiters
set i to 1 -- Column variable.
set x to 1 -- File variable.
set newLine to ASCII character 10
set theDir to (choose folder with prompt "Pick the folder containing the .OCW files you would like copied into Excel:") as string
set theDir2 to alias theDir
tell application "Finder"
	set fileList to (get every item in theDir2 whose name ends with ".ocw") -- Getting all files.
	set sortedList to (sort (items of fileList) as alias list by name) -- Making alphabetical.
end tell
set amountofFiles to the number of items of sortedList
repeat while x is less than or equal to amountofFiles -- Setting initial repeat loop to make sure all files in the folder are processed.
	set n to 1 -- Items of file variable.
	set theName to (name of item x) of sortedList
	tell application "Microsoft Excel" -- Setting the first cell of the first column of the column pair to the name of file.
		set value of cell 1 of column (((i + i) - 1) as integer) of active sheet to theName
	end tell
	set thePath to item x of sortedList
	set theFile to thePath as alias
	set theData to (read theFile as «class utf8» from 10) -- There's some spaces and an apostrophe I don't want putting into Excel.
	set valuePairs to every paragraph of theData
	set theValues to every item of valuePairs
	set theAmount to the number of items of valuePairs
	set AppleScript's text item delimiters to space
	repeat while n is less than or equal to theAmount -- Making sure all pairs of values of the values are processed.
		set onePair to the item n of theValues
		set valueItems to text items of onePair
		if number of items of valueItems is equal to 3 then -- Depending how the numbers are structured they leave behind more or less "" meaning a and b must be set differently.
			set a to item 1 of valueItems
			set b to item 2 of valueItems
		else if number of items of valueItems is equal to 5 then
			set a to item 3 of valueItems
			set b to item 4 of valueItems
		else if number of items of valueItems is equal to 6 then
			set a to item 3 of valueItems
			set b to item 5 of valueItems
		end if
		tell application "Microsoft Excel"
			set value of cell (n + 1) of column (((i + i) - 1) as integer) of active sheet to a
			set value of cell (n + 1) of column ((i + i) as integer) of active sheet to b
		end tell
		set n to (n + 1) -- Next value pair.
	end repeat
	if n is equal to (theAmount + 1) then -- Is this the last value pair of the file? If so, move onto the next file.
		set x to (x + 1)
		set i to (i + 1) -- Next value pair will go into the next pair of columns in Excel
	end if
	if ((x - 1) mod 4) is equal to 0 then -- If there has been four value pairs inserted into Excel, then leave a gap (I want scans 1, 2, 3, and 4 together).
		set i to (i + 1) -- Leaves the gap.
	end if
-- GRAPH CHUNK GOES HERE
end repeat
set AppleScript's text item delimiters to tid
beep 2
tell application "Microsoft Excel"
	display dialog "Done!" with icon note
end tell

The Graph Chunk - (basically C/P’d from the MS Dev site)

tell application "Microsoft Excel"
		--Create chart object
		set oChartObj to make new chart object at end ¬
			with properties {left position:400, top:100, width:500, height:400} ¬
			
		
		--Now build the Chart within the ChartObject
		tell chart of oChartObj
			set chart type to xy scatter smooth -- define chart type
			
			-- add each series
				set newSeries to make new series at end ¬
					with properties {series values:¬
					(column (i + i)), xvalues:¬ -- If I do this, then Excel errors saying I can't have a series with more than 32, 000 values...
					(column ((i + i) - 1)), name:¬ -- I assume it's saying this because it assumes I don't want just the cells with data in from the columns, I want the empty cells too... -_-
					(A Name)}
				--  need to specify _value_ (no default property)                                   
			end repeat
			
			--'Add Titles and Format Chart and Axes
			set has title to true
			tell its chart title -- needs 'its !!
				set caption to "My XY Scatter Chart"
				tell font object
					set name to "Verdana"
					set font size to 12
					set bold to true
				end tell
			end tell
			
			set categoryAxis to get axis axis type category axis ¬
				which axis primary axis
			tell categoryAxis
				set has title to true
				tell its axis title -- needs 'its' !!
					set caption to "X Values"
					tell font object
						set name to "Verdana"
						set font size to 10
						set bold to true
					end tell
				end tell
			end tell
			
			set valueAxis to get axis axis type value axis ¬
				which axis primary axis
			tell valueAxis
				set has title to true
				tell its axis title -- needs 'its' !!
					set caption to "Y Values"
					tell font object
						set name to "Verdana"
						set font size to 10
						set bold to true
					end tell
				end tell
			end tell
			
			--'Format Plot area
			tell plot area object
				tell its border -- needs its
					set color to {0, 0, 255}
					-- will this work?, if not:
					--set its color index to 5
				end tell
				tell its chart fill format object
					set visible to true
					--set fore color to {150, 200, 255} 
					--can't set color
					--set transparency to 0.5
					set foreground scheme color to 23
					set transparency to 0.8 -- the same color
				end tell
			end tell
			
			--format legend
			set has legend to false

		end tell
	end tell
end tell

Model: MacBook 2,1
AppleScript: 2.0.1
Browser: Firefox 3.5.1
Operating System: Mac OS X (10.5)

Instead of saying “column 1” say “item 1 of columnLetters”… something like this where the column numbers are the index numbers of letters in a list.

set columnLetters to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}

tell application "Microsoft Excel"
	tell active sheet
		--set theRange to {column 1, cell 1}
		--set theRange2 to {column 2, cell 6}
		set theRange to item 1 of columnLetters & "1"
		set theRange2 to item 2 of columnLetters & "6"
		set the actualRange to (theRange & ":" & theRange2)
	end tell
end tell
--> "A1:B6"

Here are two ways to refer to a cell.

tell application "Microsoft Excel"
	
	set oneWay to range ("B" & 8) of active sheet
	-- Return: cell "B8" of active sheet of application "Microsoft Excel"
	
	set twoWay to cell 8 of (column 2 of active sheet)
	-- Return: column "$B$8" of column 2 of active sheet of application "Microsoft Excel"

	
end tell

Thanks for the replies guys!

regulus633, I thought of this way, but I have more than 26 files so I hit a snag when I come to the “AA” column in Excel. Otherwise it would be perfect!

mikerickson, how am I supposed to increment “B” algebraically? The reference can’t directly use a letter or it won’t work in my script. Also, whilst I know you can specify a cell like that, I cannot coerce this into a range. That’s my problem. See below:

tell application "Microsoft Excel"
	set theRange to cell 8 of (column 2 of active sheet)
	set theRange2 to cell 8 of (column 1 of active sheet)
	set actualRange to range {theRange, theRange2}
end tell

OR

tell application "Microsoft Excel"
	set theRange to cell 8 of (column 2 of active sheet)
	set theRange2 to cell 8 of (column 1 of active sheet)
	set actualRange to (theRange & ":" & theRange2)
end tell

I don’t understand what the problem is.
If you want to incriment a range, the get offset command would work.

to incriment a letter, “character id ((id of “B”) + 1)”

When I ran those two scripts, there was no value returned for actualRange.
What value do you want it to be?

That get offset command looks interesting! It would work up until Excel started using the double-letter columns “AA, AB, AC”, etc. Is there a way it could work with that?

Precisely. It’s because the two variables cannot be combined because there is a conflict with their classes. I want/need them to be combined! :slight_smile: That way I can still specify the column algebraically, e.g (cell x of (column (y)), but then coerce them into an absolute range like “$A$1:$B$8”. (The range can also be relative, like in regulus6633’s response).

Do you see what I’m getting at now?

Your help is very appreciated! :slight_smile:

Perhaps

tell application "Microsoft Excel"
	set theRangeAddress to get address of (cell 8 of (column 2 of active sheet)) with external
	
	set theRangeAddress2 to get address of (cell 8 of (column 1 of active sheet)) with external
	set actualRange to my RangeBoundedBy(theRangeAddress2, theRangeAddress)
	
end tell

on RangeBoundedBy(topLeftCell, bottomRightCell)
	tell application "Microsoft Excel"
		set topLeftCell to range topLeftCell
		
		set bottomRightCell to range bottomRightCell
		
		set columnsCount to (first column index of bottomRightCell) - (first column index of topLeftCell) + (count of columns of bottomRightCell)
		
		set rowsCount to (first row index of bottomRightCell) - (first row index of topLeftCell) + (count of rows of bottomRightCell)
		
		set EnclosedRange to get resize topLeftCell row size rowsCount column size columnsCount
		
		return EnclosedRange
	end tell
end RangeBoundedBy

This has been bugging me. I think I’ve got it figured out.

This avoids the work-around that I used above

tell application "Microsoft Excel"
	set theRange to cells of (cell 8 of (column 2 of active sheet))
	set theRange2 to cells of (cell 8 of (column 1 of active sheet))
	set actualRange to range ((get address of theRange) & ":" & (get address of theRange2))
end tell

That’s fantastic stuff, mikerickson! I’m awed by your scripting skills! :o

As I (embarrassingly) wasn’t too sure how to put that reference into a chart’s series, I modified it a bit so I had just “A*:A*” and “B*:B*”. The graphs that result are almost perfect - I just want to know two things: Firstly, how do I automatically get Excel to place each new graph on a new sheet (i.e. “Chart 1, 2, 3, etc.”) before “Sheet1”? And secondly, how do I get the tick mark position of the x-axis to be low? I tried adding “set tick label position high” under the “tell categoryAxis” part, but I kept getting errors. The MS Dev site really isn’t very helpful. Here’s the full script (feel free to test on those sample files I provided):

set AppleScript's text item delimiters to ""
set tid to AppleScript's text item delimiters
set i to 1
set x to 1
set newLine to ASCII character 10
set theDir to (choose folder with prompt "Pick the folder containing the .OCW files you would like copied into Excel:") as string
set theDir2 to alias theDir
tell application "Finder"
	set fileList to (get every item in theDir2 whose name ends with ".ocw")
	set sortedList to (sort (items of fileList) as alias list by name)
end tell
set amountofFiles to the number of items of sortedList
repeat while x is less than or equal to amountofFiles
	set n to 1
	set theName to (name of item x) of sortedList
	tell application "Microsoft Excel"
		set value of cell 1 of column (((i + i) - 1) as integer) of active sheet to theName
	end tell
	set thePath to item x of sortedList
	set theFile to thePath as alias
	set theData to (read theFile as «class utf8» from 10) -- 3 if there's no apostrophe in the .ocw, 10 if there is! This is what causes the "a is not defined" error!
	set valuePairs to every paragraph of theData
	set theAmount to ((the number of items of valuePairs) - 1)
	set AppleScript's text item delimiters to space
	repeat while n is less than or equal to theAmount
		set onePair to the item n of valuePairs
		set valueItems to text items of onePair
		if number of items of valueItems is equal to 3 then
			set a to item 1 of valueItems
			set b to item 2 of valueItems
		else if number of items of valueItems is equal to 5 then
			set a to item 3 of valueItems
			set b to item 4 of valueItems
		else if number of items of valueItems is equal to 6 then
			set a to item 3 of valueItems
			set b to item 5 of valueItems
		end if
		tell application "Microsoft Excel"
			set value of cell (n + 1) of column (((i + i) - 1) as integer) of active sheet to a
			set value of cell (n + 1) of column ((i + i) as integer) of active sheet to b
		end tell
		set n to (n + 1)
	end repeat
	if n is equal to (theAmount + 1) then
		set x to (x + 1)
		set i to (i + 1)
	end if
	if ((x - 1) mod 4) is equal to 0 then -- Change the mod number depending upon the amount of scans made per scan rate!
		set i to (i + 1)
	end if
	tell application "Microsoft Excel"
		
		set theRange1st to cells of (cell 2 of (column 1 of active sheet))
		set the2Range1st to cells of (cell 10 of (column 1 of active sheet))
		set actualRange1st to range ((get address of theRange1st) & ":" & (get address of the2Range1st))
		
		set theRange2nd to cells of (cell 2 of (column 2 of active sheet))
		set the2Range2nd to cells of (cell 10 of (column 2 of active sheet))
		set actualRange2nd to range ((get address of theRange2nd) & ":" & (get address of the2Range2nd))
		
		tell active sheet
			
			--Create chart object
			set oChartObj to make new chart object at end ¬
				with properties {left position:400, top:100, width:500, height:400} ¬
				
			--Now build the Chart within the ChartObject
			tell chart of oChartObj
				set chart type to xy scatter smooth -- define chart type
				
				set newSeries to make new series at end ¬
					with properties {series values:¬
					(actualRange2nd), xvalues:¬
					(actualRange1st)}
				--  need to specify _value_ (no default property)
				
				--'Add Titles and Format Chart and Axes
				set has title to true
				tell its chart title -- needs 'its !!
					set caption to (theName)
					tell font object
						set name to "Helvetica"
						set font size to 12
						set bold to true
					end tell
				end tell
				
				set categoryAxis to get axis axis type category axis ¬
					which axis primary axis
				tell categoryAxis
					set has title to true
					tell its axis title -- needs 'its' !!
						set caption to "Potential (V)"
						tell font object
							set name to "Helvetica"
							set font size to 11
							set bold to false
						end tell
					end tell
				end tell
				
				set valueAxis to get axis axis type value axis ¬
					which axis primary axis
				tell valueAxis
					set has title to true
					set has major gridlines to false
					tell its axis title -- needs 'its' !!
						set caption to "Current (A)"
						tell font object
							set name to "Helvetica"
							set font size to 11
							set bold to false
						end tell
					end tell
				end tell
				
				--format legend
				set has legend to false
				
			end tell
		end tell
	end tell
end repeat
set AppleScript's text item delimiters to tid
beep 2
tell application "Microsoft Excel"
	display dialog "Done!" with icon note
end tell

In addition, is there any advice you could give me regarding making this script more streamlined?

Thank you very much for your help so far! :slight_smile:

I don’t work with charts much. You might consider creating chart sheets rather than imbedding chart objects in worksheets.

Scripts like

tell application "Microsoft Excel"
	move sheet "Chart1" of active workbook to before sheet 1
end tell

can move them to the order that you want.

How do I create a chart without the chartObject? The chartObject seems a necessary precursor. Thanks for that scriplet :slight_smile:

Do I simply add in

set chartSheet to make new chart sheet at beginning of active workbook

instead of

set oChartObj to make new chart object at end ¬
				with properties {left position:400, top:100, width:500, height:400

Then do I do:

tell chart of chartSheet

Thanks!

I don’t work with charts, but fiddling around got me this syntax to add a chart sheet

tell application "Microsoft Excel"
	
	make new chart at beginning of active workbook
	
end tell

I’ve got the chart being added as a new sheet now, in the right order (thanks), but annoyingly the source data seems that it needs to be set differently from when you embed the chart!! Argghh. Do you think you could help me fix this? I’ve tried two ways without success.

This is the first one:

	tell application "Microsoft Excel"
		
		set theRange to cells of (cell 2 of (column 1 of sheet 1))
		set theRange2 to cells of (cell 10 of (column 2 of sheet 1))
		set actualRange to range ((get address of theRange) & ":" & (get address of theRange2))
		
		set chartSheet to make new chart sheet at end of active workbook
		set theChart to chart of chartSheet
		set source data theChart source range actualRange plot by columns -- This line was highlighted by the error message.
		
		tell chart of chartSheet
			set chart type to xy scatter smooth -- define chart type
			
			--'Add Titles and Format Chart and Axes
			set has title to true
			tell its chart title -- needs 'its !!
				set caption to (theName)
				tell font object
					set name to "Helvetica"
					set font size to 12
					set bold to true
				end tell
			end tell
			
			set categoryAxis to get axis axis type category axis ¬
				which axis primary axis
			tell categoryAxis
				set has title to true
				tell its axis title -- needs 'its' !!
					set caption to "Potential (V)"
					tell font object
						set name to "Helvetica"
						set font size to 11
						set bold to false
					end tell
				end tell
			end tell
			
			set valueAxis to get axis axis type value axis ¬
				which axis primary axis
			tell valueAxis
				set has title to true
				set has major gridlines to false
				tell its axis title -- needs 'its' !!
					set caption to "Current (A)"
					tell font object
						set name to "Helvetica"
						set font size to 11
						set bold to false
					end tell
				end tell
			end tell
			
			--format legend
			set has legend to false
			
		end tell
		
		select chart sheet (get count of chart sheets)
		set name of active chart to (theName)
		
	end tell

ERROR: Microsoft Excel got an error: chart of chart sheet “Chart1” of active workbook doesn’t understand the set source data message.

And I tried this way:


	tell application "Microsoft Excel"
		
		set theRange1st to cells of (cell 2 of (column 1 of sheet 1))
		set the2Range1st to cells of (cell 10 of (column 1 of sheet 1))
		set actualRange1st to range ((get address of theRange1st) & ":" & (get address of the2Range1st))
		
		set theRange2nd to cells of (cell 2 of (column 2 of sheet 1))
		set the2Range2nd to cells of (cell 10 of (column 2 of sheet 1))
		set actualRange2nd to range ((get address of theRange2nd) & ":" & (get address of the2Range2nd))
		
		set chartSheet to make new chart sheet at end of active workbook
		
		tell chart of chartSheet
			set chart type to xy scatter smooth -- define chart type
			
			set newSeries to make new series at end ¬ -- This part
				with properties {series values:¬ -- was highlighted
				(actualRange2nd), xvalues:¬ -- by the error
				(actualRange1st)}-- message.
			
			--'Add Titles and Format Chart and Axes
			set has title to true
			tell its chart title -- needs 'its !!
				set caption to (theName)
				tell font object
					set name to "Helvetica"
					set font size to 12
					set bold to true
				end tell
			end tell
			
			set categoryAxis to get axis axis type category axis ¬
				which axis primary axis
			tell categoryAxis
				set has title to true
				tell its axis title -- needs 'its' !!
					set caption to "Potential (V)"
					tell font object
						set name to "Helvetica"
						set font size to 11
						set bold to false
					end tell
				end tell
			end tell
			
			set valueAxis to get axis axis type value axis ¬
				which axis primary axis
			tell valueAxis
				set has title to true
				set has major gridlines to false
				tell its axis title -- needs 'its' !!
					set caption to "Current (A)"
					tell font object
						set name to "Helvetica"
						set font size to 11
						set bold to false
					end tell
				end tell
			end tell
			
			--format legend
			set has legend to false
			
		end tell
		
		select chart sheet (get count of chart sheets)
		set name of active chart to (theName)
		
	end tell
end repeat
beep 2
tell application "Microsoft Excel"
	display dialog "Done!" with icon note
end tell
set AppleScript's text item delimiters to tid

ERROR: Microsoft Excel got an error: Can’t make class series.

I appreciate you don’t normally work with graphs :slight_smile:

P.S.

Bear in mind the script I posted in post #9 works perfectly when the graph is embedded… it just won’t work for the chart within the chart sheet for some reason… I’d also be perfectly happy if you told me how I could take an embedded chart, and put it in its own new sheet. I couldn’t figure out the syntax. Moving it, or creating it in a purpose-built sheet - either solution works for me :slight_smile: