Hi Rob,
(You are using an HTML-capable email client, right? Otherwise, please
let me know and I'll get this email in suitable format.)
I'm trying to illustrate how to use Mystique to code (most of) the
table graphics I showed you last Thursday from Tufte's "The Visual
Display of Quantitative Information", p.174, reproduced here
for your convenience. I think this code probably needs some explanation
in person, but I'd just like to ask for your first impression, mainly
whether it's too complicated or not for the task that it does.
In addition, I have another idea (here)
in the "breaking windows" theme for viewing this piece of code. In most
languages, the linear order by which things in a method body need to be
declared often clashes with the hierarchical strategy that humans use
to understand the code. My idea is to break that linear order and show
code fragments where they start to be "useful". In this example, the
function processHalfBatch is declared linearly before the for loop, but
it's shown on the right of the for loop. My argument is that a
programmer wishing to understand the function foo:presentChart is
likely to read the for loop first to get the overall picture and then
dive into the various utility inner functions. This method of
visualizing foo:presentChart helps her do that; otherwise, she must
scan over most of the method body before reaching the for loop. Perhaps
we can term this "micro software visualization". I'm CCing Vineet just
in case he's interested.
Thanks!
David
@prefixJavaPackage XHTML edu.mit.csail.haystack.monet.subsyntax.XHTML
function foo:presentChart(List carModels,
List years, List parts){
XHTML overallTableHTML = xhtml:{
<table id="theTable"></table> }
XHTML!Table overallTable =
overallTableHTML.getElementByID("theTable")
List yearsRow = map(years,
function: (Resource year) as
XHTML {
return subst(xhtml:{ <span>{%1, view of year}</span> },
monet:present(year))
}
)
XHTML partColumnHTML = xhtml:{
<table
id="theTable"><tr><td><b>Trouble
Spots</b></td></tr></table> }
List rows = map(parts,
function: (Resource p)
as XHTML {
View partView = monet:present(p)
return subst(xhtml:{
<tr><td
align="center">{%1}</td></tr> }, partView)
}
)
partColumnHTML.getElementByID("theTable").insertRows(rows)
Function processCarPart = function:(Resource
car, Resource part) as XHTML {
XHTML partRowHTML = xhtml:{ <tr></tr> }
XHTML!TableRow partRow = partRowHTML.getRootElement()
partRow.addCells(map(years,
function:(Resource year) {
String quality = ...code to
retrieve quality from car, part, and year...
SVG circle = svg:{
<svg width="2ex" height="2ex"
text-baseline="0em"></svg> }
select quality
case "much better
than average"
circle.getRootElement().addChild(
svg:{ <circle cx="1em" cy="1em" r="1em" style="stroke:
black 1pt"></circle> }
)
case
"better than average"
circle.getRootElement().addChild(
svg:{ <circle cx="1em" cy="1em" r="1em" style="stroke:
black 0.15em"></circle> }
)
case
"average"
circle.getRootElement().addChild(
svg:{ <circle cx="1em" cy="1em" r="1em" style="stroke:
black 0.3em"></circle> }
)
case
"worse than average"
circle.getRootElement().addChild(
svg:{ <circle cx="1em" cy="1em" r="1em" style="stroke:
black 0.5pt"></circle> }
)
case
"much worse than average"
circle.getRootElement().addChild(
svg:{ <circle cx="1em" cy="1em" r="1em" style="fill:
black"></circle> }
)
return subst(xhtml:{ <td>{%1}</td>
}, circle)
}
))
return partRowHTML
}
Function processHalfBatch = function:(XHTML
rowHTML, List carModels) {
List cells = map(carModels,
function: (Resource car) as
XHTML {
XHTML carTableHTML = subst(xhtml:{
<table
id="theTable">
<tr><td colspan="{%1}"
align="center"><b>{%2, view of
car}</b></td></tr>
</table>
},
years.size(),
monet:present(car)
)
XHTML!Table carTable =
carTableHTML.getElementByID("theTable")
carTable.addRow(yearsRow)
carTable.addRows(map(parts, processCarPart(car)))
}
)
rowHTML.addCells(cells)
}
for batch
in List.breakIntoBatches(carModels, 6)
XHTML rowHTML = xhtml:{ <tr id="theRow"></tr> }
List firstHalf = batch.getItems(0, 3)
processHalfBatch(rowHTML, firstHalf)
rowHTML.getElementByID("theRow").addCell(subst(xhtml:{ <td>{%1}</td>
}, partColumnHTML))
List secondHalf = batch.getItems(3, 3)
processHalfBatch(rowHTML, secondHalf)
overallTable.addRow(rowHTML)
monet:present(
overallTableHTML,
^monet:pe as
monet:PresentationEnvironment
)
}