Wednesday, April 02, 2008

Next Time Think of Some Tests

If you volunteer to help your sister-in-law with wedding preparations on Thursday, and you don't get to it until Friday, and you decide to write a program to do it, don't forget to think about some basic sanity checks on the final output. Otherwise on Sunday you'll hear from your father-in-law wondering why some people didn't have placecards and didn't know where to sit.

So yeah, wedding preparations in the sense of "can you research how to go from an Excel spreadsheet of names and table assignments to a Word document with the names in the right places to print on these pre-scored placecard sheets from Hobby Lobby, SKU #717694."

The more you think about Excel, you think "Not too bad, Mathematica imports from Excel," and the more you think about Word you think "Ugh". And the more you think about Mathematica, the more you remember the vector graphics language, and that you can trivially export to PDF or rasterized image files.

tables = Import["c:/tables.xls"];
sheet = First[tables];
(* Extract name from row by pattern match *)
nameOfRow[{title_, names_, ___}] :=
trim[title] <> " " <> trim[names];
(* extract table assignment text from row *)
tableOfRow[{_, _, _, tbl_, ___}] := trim[tbl];
(* filter out blank rows *)
rowsWithNames[sheet_] := Select[sheet,
Function[row, trim[row] =!= ""]];
Some Opening Lines of Code, Which May Become Important Later

Not very long after, it seems, the Excel spreadsheet is imported, blank rows are skipped, the names and table numbers are constructed and placed onto the vectorized layout of the placecard sheet, with or without preview construction lines. Very cool.

placecardPageTemplate[] :=
With[{w = placecardPageWidth, h = placecardPageHeight,
pgborder = placecardPageBorder},
(* Solid page border *)
Dashing[{}], Line[{{0, 0}, {w, 0}, {w, h}, {0, h}, {0, 0}}],

(* Scored page borders *) Dashed,
Line[{{pgborder, 0}, {pgborder, h}}],
Line[{{w - pgborder, 0}, {w - pgborder, h}}],
Line[{{0, pgborder}, {w, pgborder}}],
Line[{{0, h - pgborder}, {w, h - pgborder}}],

(* Scored between-card borders *)
(* vertical *) Line[{{w/2, 0}, {w/2, h}}]}
Table[With[{cardHt = pgborder + i*placecardHeight},
Line[{{pgborder, cardHt}, {w - pgborder, cardHt}}]], {i, 1, 2}]
Flatten[Table[placecardTemplate[r, c],
{c, 1, numPlaceCardColumns},
{r, 1, numPlaceCardRows}], 2]];
Sample of the Vector Graphics Code

More time is spent rasterizing, with long interruptions for meals, toddler nap and bedtime, and the necessary socializing that comes from being in the bride's family's house the day before the wedding (e.g. rehearsal and dinner).

By late evening the table assignments are finalized and the requested high-resolution JPGs are being rasterized from the vector graphic objects. Sometime the next morning, the placecards are printed. The ceremony comes off with only one hitch, and by evening the reception is ready to swing.

Except... for that one little hack. When you wrote that simple filter to remove blank rows, you did it by checking if the first column was blank. And as it turns out, the first column is for titles and some names, about 6, didn't have a title.

Fault? Everyone agreed it was the you the programmer's. Some issue can be made about the the given spreadsheet format, with a separate column for titles. But the bottom line is you had all the data, and simply spent too much time coding and not enough time planning. There was time to do it right, and no time to do it over. There should have been some time devoted up front to thinking about how to check for correctness of the final output.

Oh well. The next time someone asks to help print placecards you're all set...

If you are interested in the Mathematica notebook that can generate custom placecards with your database of names, send to the account jfkbits. And please note I've fixed the aforementioned bug.

No comments: