-- Script for PublishPlot -- Replot and the curves in the current plot as a stack plot in a new window -- Set color of each curve in source plot, then run this script -- Get stacked plots filled with colors and black lines on the borders -- For bar charts, set symbol fill color of each -- Note that output is a numeric plot and not a bar chart -- Written by John A. Nairn, 12/1/2020 global xmin, xmax, ymin, ymax global xlab, ylab, psize tell application "PublishPlot" -- needs a document with data activate if number of documents is 0 then display dialog "No open documents" return end if -- get data from source docunment set source to front document tell source -- need at least two curves to stack set numCurves to number of plots if numCurves < 2 then display dialog "Open a document with multiple curves or bar charts and try again" return end if set xtype to bar chart -- find range of x values for all plots repeat with i from 1 to numCurves set lims to get limits of plot i set x1 to item 2 of lims set x2 to item 3 of lims set y1 to item 5 of lims if i = 1 then set xmin to x1 set xmax to x2 set ymin to y1 else if x1 < xmin then set xmin to x1 else if x2 > xmax then set xmax to x2 end if if y1 < ymin then set ymin to y1 end if end repeat -- stack is for positive plots only if ymin < 0 then display dialog "All plot values must be nonnegative" return end if -- get axes and size set xlab to label of x title set ylab to label of y title set psize to plot size end tell end tell if xtype is true then stackCharts(source, numCurves) else stackPlots(source, numCurves) end if on stackPlots(source, numCurves) tell application "PublishPlot" -- We store the stack sum in xpt and ypt using npts points -- set x values and initialize y to 0 set xpt to {} set ypt to {} set npts to 100 set delta to (xmax - xmin) / (npts - 1) repeat with i from 1 to npts set end of xpt to xmin + (i - 1) * delta set end of ypt to 0 end repeat -- store tables for all plots set hdrs to {} set hdrs2 to {} set plts to {} -- repeat for each curve repeat with ic from 1 to numCurves -- gfab curve from the source document tell source set pts to sorted data of plot ic set ipts to number of items in pts set pname to name of plot ic set pclr to (object color of plot ic) end tell -- loop over points locations for stack data set k0 to 1 repeat with i from 1 to npts - 1 -- next stacked data location set x to item i of xpt -- loop to find interval for where x x then -- found x(k-1) < x < xk -- if k=1 curve to add not started yet, set it to zero if k > 1 then -- interpolate add add to stacked sum set x1 to item 1 of (item (k - 1) of pts) set y1 to item 2 of (item (k - 1) of pts) set yk to item 2 of (item k of pts) set yval to y1 + (x - x1) * (yk - y1) / (xk - x1) set yprev to item i of ypt set item i of ypt to yprev + yval -- points are sorted so start here next time set k0 to k end if exit repeat end if end repeat end repeat -- do last point as a special case, but onl if at xmax set xk to item 1 of (last item of pts) if xk ³ xmax then set yval to item 2 of (last item of pts) set yprev to last item of ypt set last item of ypt to yprev + yval end if -- start table for filled curve and include xmin in needed set sdata to {} set end of sdata to "#setLineType" & tab & "filled" & return set rgb to "\"" & (item 1 of pclr) / 65535 & " " & (item 2 of pclr) / 65535 & " " & (item 3 of pclr) / 65535 & "\"" set end of sdata to "#setColor" & tab & rgb & return set end of sdata to "#setName" & tab & "\"" & pname & "(line)\"" & return if item 1 of ypt > 0 then set end of sdata to (item 1 of xpt) & tab & "0" & return end if set end of hdrs to sdata -- save header to draw the line set sdata to {} set end of sdata to "#setName" & tab & "\"" & pname & "\"" & return set end of hdrs2 to sdata -- get data points in a list set sdata to {} repeat with i from 1 to npts set end of sdata to (item i of xpt) & tab & (item i of ypt) & return end repeat set end of plts to sdata end repeat -- create new window make new document set dest to front document -- plot curve in reverse order tell dest set label of x title to xlab set label of y title to ylab set plot size to psize repeat with ic from numCurves to 1 by -1 -- filled curve using color of original plot set myTable to (item ic of hdrs) as string set myTable to myTable & ((item ic of plts) as string) set myTable to myTable & (last item of xpt) & tab & "0" & return set dset to plot table data myTable -- black line between plots set myTable to (item ic of hdrs2) as string set myTable to myTable & ((item ic of plts) as string) set dset to plot table data myTable end repeat end tell end tell end stackPlots on stackCharts(source, numCurves) set numBars to round (xmax + 0.5) rounding down -- initialize data to stacked bars -- this will hold labels and current stack sum set xpts to {} set ypts to {} repeat with i from 1 to numBars set end of xpts to "" set end of ypts to 0 end repeat -- store tables for plotting set tbls to {} tell application "PublishPlot" -- repeat for each curve repeat with ic from 1 to numCurves -- grab curve from the source document tell source set pts to plot data of plot ic set pname to name of plot ic set pclr to (symbol fill color of plot ic) end tell -- data for current plot set xname to item 1 of pts set yval to item 2 of pts -- arrays to sum points set xnum to {} set ysum to {} repeat with i from 1 to numBars set end of xnum to 0 set end of ysum to 0 end repeat repeat with i from 1 to (number of items in xname) -- get text for this data point set xtext to item i of xname -- find index to xtext in xpts (or insert it if not found) repeat with j from 1 to numBars set ctext to item j of xpts if ctext is "" then -- insert into list set item j of xpts to xtext set ib to j exit repeat else if ctext is xtext then -- found list index set ib to j exit repeat end if end repeat -- add to sums at index ib set item ib of xnum to (item ib of xnum) + 1 set item ib of ysum to (item ib of ysum) + (item i of yval) end repeat -- calculate means repeat with i from 1 to numBars set xtot to item i of xnum if xtot > 0 then set ytot to item i of ysum set item i of ypts to (item i of ypts) + ytot / xtot end if end repeat -- create table using current values set sdata to {} set end of sdata to "#setLineType" & tab & "none" & return set rgb to "\"" & (item 1 of pclr) / 65535 & " " & (item 2 of pclr) / 65535 & " " & (item 3 of pclr) / 65535 & "\"" set end of sdata to "#setSymbolLineWidth" & tab & "0.25" & return set end of sdata to "#setSymbolFillColor" & tab & rgb & return set end of sdata to "#setSymbolType" & tab & "\"Vertical Bar\"" & return set end of sdata to "#setName" & tab & "\"" & pname & "(line)\"" & return -- add the points repeat with i from 1 to numBars set xtext to item i of xpts if xtext is "" then exit repeat set end of sdata to i & tab & (item i of ypts) & return end repeat -- add to tables set end of tbls to sdata end repeat -- create new window make new document set dest to front document -- get symnbol size set hw to (item 2 of psize) / (item 1 of psize) set hw to 1 + hw * hw set sym to 70 / ((numBars + 1) * (hw ^ 0.5)) -- plot curve in reverse order tell dest set label of x title to xlab set label of y title to ylab set plot size to psize repeat with ic from numCurves to 1 by -1 -- filled curve using color of original plot set myTable to (item ic of tbls) as string set dset to plot table data myTable repeat while refreshed is false end repeat end repeat -- symbol size repeat with i from 1 to numCurves set symbol size of plot i to sym end repeat -- make sure is done set automatic of x scale to false set ticks of x scale to {0, numBars + 1, 1, 0} set yticks to ticks of y scale set item 1 of yticks to 0 set automatic of y scale to false set ticks of y scale to yticks -- bar labels set object color of x scale to "white" repeat with i from 1 to numBars set btext to item i of xpts set blab to (add label annotation btext position {i, 0}) set lsize to text size of blab set lpt to position of blab set shft to 0.55 * (item 2 of lsize) set item 2 of lpt to (item 2 of lpt) - shft set position of blab to lpt end repeat end tell end tell end stackCharts