Main index Other Papers index About author

Valid HTML 4.01 Transitional

Glasses placemat: how to avoid confusion at a port tasting

Julian D. A. Wiseman

Contents: Publication history; example output (and in PDF); How to control the PostScript program; Other easy parameters; Non-easy parameters; Code within parameters; Errors: causation and avoidance; How to comment; Who to invite?; Recent changes.

Publication history: only at Usual disclaimer and copyright terms apply. Also see the main feature, the PostScript program itself.

This is the ‘documentation’, such as it is, for the latest version, dated February 2015, which prior precedent suggests will not be the last. The code is mostly debugged, but errors surely remain. It is provided as-is, without liability—it is free.

Also see the complete list of previous placemats, some with comments; the advice about choosing of the page size; the obscure parameters; how to use code in parameters; /TimesNewRomanPS-BoldMT’s accented characters and their PostScript glyphs, which includes diacritics as well as accents. Further, PostScript programmers are invited to peruse the infrequently updated list of re-usable routines.


So you and your lucky guests are to enjoy a port tasting. Of course, there will be many glasses, each person having one for each port. But it is important to avoid the what-is-in-this-glass confusion: each person will need a wine tasting placemat, clearly labelling each glass’s spot.

The author has devised a PostScript program to create such pages, and all the other paperwork required to manage such tastings, large or small. Glasses pages are set as in the PDF example, the first two pages of which (to hold the glasses, and on which to write tasting notes) are also rendered immediately below.

Example of an 8-glass port tasting placemat Example of tasting-notes sheet

 Making Your First Placemat: Advice for Beginners

Don’t try to make your first placemats with little time to spare. Start a week in advance, to allow time for learning and improvements, and to avoid the other things that need doing just before a tasting. Yes, it can be done in a few minutes—but not your first placemats.

A code editor, a good text editor, is a boon, and it should be one that understands PostScript. The basic text editor that came pre-installed on your computer will make life harder than it needs to be. A code editor that understands PostScript will prevent many errors and save much labour. On a PC NotePad++ is good. On a Mac: Alpha X is excellent and free, though not perfectly coping with OS versions ≥10.9; Aquamacs Emacs is suitable for Emacs experts; Sublime Text 3 seems good, but making it understand PostScript requires a technical step.

Bookmark this manual, and download to your machine a copy of the PostScript code (update this copy every time: new versions fix bugs; add features; improve default settings). Store it in a directory named something like “placemats”. Make a copy of the original PostScript. Give it a name which will make sense in aeons to come: perhaps, or Perhaps see the files names in the list of old placemats.

You have saved a .ps file. This file is to be opened in two different ways: with the code editor; and with a program to convert it from .ps to .pdf. Let’s master the latter. On a Mac right-click the file, and ‘Open With’ Preview. It should convert to a PDF. On a PC, in your preferred web browser, open; ‘Select files…’; and ‘Convert’ it. You can now convert the PostScript to PDF.

Open the file with the code editor, perhaps by right-clicking and choosing from the ‘Open With’ applications (Alpha, Notepad++, whatever). For a sense of which of the many features might be wanted look at the example placemats, or the complete list of old placemats, some of which have helpful comments and advice. Then use the text editor to edit the copy of the PostScript, changing to values appropriate for your tasting the:

Convert to PDF, to test that all is well.

If decanter labels are wanted, set DecanterLabelsNumCopies to 1. Also alter, as necessary, PlaceNames, PrePourNumCopies, DecantingNotesNumCopies, CorkDisplay, VoteRecorders, or StickyLabelsNumCopies and StickyLabelsTypes.

Now set InlineTitles to false and replace with some of the more exuberant glass-decoration features described in this manual. Play and experiment. Convert to PDF after each significant change, and admire the results. Choose a small subset of the decorative features to go in the final placemats. Too many flamboyant features looks cluttered and horrible, so be parsimonious. Perhaps change the the fonts—a list of valid PostScript font names being most easily made by distilling Convert to PDF.

If the tasting is being arranged via ThePortForum or another wine bulletin board, upload the PDF to the web, and post in an appropriate thread a link labelled something like “Current draft of the placemats”. Allow some time for comments and corrections and changes. Update if appropriate.

Perhaps send to the author links to the .ps and .pdf. Time and convenience permitting, help might be forthcoming. Please send the URLs of the uploaded .ps and .pdf files, rather than filling email with large enclosures. Allow some days for a response.

The day before the tasting print the mats using a toner printer.

Neatly fold the place-names pages, and construct the decanter labels. Cut a neat rectangle around each; paste to the back of a business card (typically one from a former employer—keep them when changing jobs); allow the glue to dry; punch holes top-left and top-right; hang on the decanter, perhaps using a 30″ metal bead chain (filling an unlabelled decanter risks needless confusion, so hang before filling).

Enjoy the tasting.

 As examples, the following link to placemats from actual tastings, or draft placemats for future tastings. Most of these were made with earlier versions of the software; some required expert use of the program’s features.

9 May 2015, 1945s BackgroundTextsGlassesTexts.
24 Dec 2014, Three tawnies SideBySideGlassesTastingNotes.
29 Oct 2014, Croft Rotate180AlternateNames.
21 Oct 2014, Ramos Pinto BackgroundTextsGlassesTexts.
22 Apr 2014, A Flight of 1966 Typical for a horizontal.
19 Dec 2013, sticky labels at the Bell Stickies replace glass sheets.
11 & 12 June 2013, AHB’s 1963 Quinquagenary Includes most of the different page types.
4 June 2013, Some blind bottles Rotation, and use of ShapesTitlesFill.
23 Apr 2013, Dirty dozen Blind on /A3.
17 Apr 2013, Oscar in London CrossHatchingTitles.
22 Mar 2013, Taylor vertical Formatting varying by ‘type’ of port.
18 Sept 2012, Sandeman Vau Abovetitles and Overtitles.
4 Sept 2012, blind ShapesTitlesFill.
25 July 2012, Olympic years at the Portuguese Embassy FlightSeparations.
2 Mar 2012, horizontal of 1980 An uncomplicated horizontal.
11 Oct 2011, semi-blind 4×4 Complicated management of the blind and a non-blind names, which were used on different pages.
19 Sept 2011, ragbag of good port; /CircletextMaxFontSizeAbsolute 5 def, an unusually small value.
Recent, from the code’s default parameters

Also see the complete list of placemats.

For some of the ≥2012 placemats, the parameters used in the construction are quoted in a thread on ThePortForum, Parameters for the placemat software. Users wishing to replicate a feature might wish to peruse the examples therein.

 How to control the PostScript program

PostScript programs are in the form of a text file, which can be interpreted by Adobe Distiller, by Preview on the Mac OS X, by GNU Ghostscript, or by any PostScript printer (though sending raw PostScript to a printer might require some technical knowledge). Several websites offer free PS→PDF conversion, including (fonts available there). The text file can be edited in any text editor, though it is easier to use a text editor that has been configured to edit PostScript files—see comment in box.

After some opening comments (after a “%” character the remainder of a line is a comment), the program defines some arrays, starting with Titles, Belowtitles, and Circlearrays. Each of these arrays has the same length, typically equal to the number of glass-settings on the page (five in the example above), and the program copes with any sensible number of glasses.

In the example provided, Titles is defined thus:

/Titles [
] def

Observe that the array is delimited with square parentheses [], and that each of the strings is delimited with round parentheses (). White space outside strings is ignored. The page looks best if each of the Titles is short, ideally ≤4 characters.

(Throughout this manual PostScript is shown in monospace with a pale grey background. Further, the preferred code editor of the author, Alpha X, helpfully colours the different types of element. That colouring is echoed here: /names; operators; array and code parentheses [ ] { }; and % comments.)

Belowtitles is an array of the same length, though, in the example, most of the strings are empty:

/Belowtitles [
] def

If an auction house is hosting the tasting, Belowtitles might contain lot numbers: (123), or even [(123) /arrowright (129)] = “123→129” (see below).

And Circlearrays, which is an array of arrays, thus:

/Circlearrays [
	[ (1963) (Graham) ]
	[ (1970) (Graham) ]
	[ (1977) (Graham) ]
	[ (1985) (Graham) (Single) ]
	[ (1985) (Graham) (Magnum) ]
] def

Each of the sub-arrays of Circlearrays contains strings. The program calculates how many copies of these sub-arrays can be spaced around the circle, and then does so with equal spacing between the elements of the sub-arrays.

Each place settings is named (e.g., the author’s “JDAW” initials are on the page shown above), and these names are listed in yet another array, not necessarily of the same length as the previous three:

/Names [
	[(G) /uacute /edieresis (st ) /Ocircumflex /ntilde /egrave]
	(Guest Two)
] def

Including a blank name, (), is very strongly recommended: last-minute changes to the guest list do happen.

Accents and modifiers: Á /Aacute á /aacute  /Acircumflex â /acircumflex À /Agrave à /agrave Å /Aring å /aring à/Atilde ã /atilde Ä /Adieresis ä /adieresis Ç /Ccedilla ç /ccedilla É /Eacute é /eacute Ê /Ecircumflex ê /ecircumflex ø /oslash (See /TimesNewRomanPS-BoldMT: accented characters and their PostScript glyphs.)

Punctuation and ligatures: ‘ /quoteleft ’ /quoteright “ /quotedblleft ” /quotedblright … /ellipsis – /endash — /emdash ‹ /guilsinglleft › /guilsinglright ‚ /quotesinglbase „ /quotedblbase fi /fi fl /fl æ /ae Æ /AE œ /oe Œ /OE ß /germandbls

Currencies, fractions, arithmetic and containment: £ /sterling € /Euro ¥ /yen (also used for CNY) ₩ /won ₪ /sheqel ¢ /cent ½ /onehalf ¼ /onequarter ¾ /threequarters ⅛ /oneeighth ⅜ /threeeighths ⅝ /fiveeighths ⅞ /seveneighths ⅓ /onethird ⅔ /twothirds ≈ /approxequal ≥ /greaterequal ≤ /lessequal ≠ /notequal × /multiply ÷ /divide ∈ /element ∉ /notelement ∋ /suchthat ∌ /notcontains

Greeks: α /alpha β /beta γ /gamma δ /delta ε /epsilon ζ /zeta η /eta θ /theta ι /iota κ /kappa λ /lambda μ /mu ν /nu ξ /xi ο /omicron π /pi ρ /rho σ /sigma τ /tau υ /upsilon φ /phi χ /chi ψ /psi ω /omega

Other: • /bullet · /periodcentered ◊ /lozenge † /dagger ‡ /daggerdbl § /section ® /registered ™ /trademark ♠ /spade ♥ /heart ♦ /diamond ♣ /club → /arrowright ← /arrowleft ↑ /arrowup ↓ /arrowdown ↔ /arrowboth ⇒ /arrowdblright ⇐ /arrowdblleft ⇑ /arrowdblup ⇓ /arrowdbldown ⇔ /arrowdblboth

Any string parameter may be replaced by an array (to make a ‘compound string’) of strings and glyphs, each glyph beginning with a forward slash (“/”). As an example, the second item of the default value of Names makes the silly but instructive “Gúëst Ôñè”. Examples of glyphs include accented characters such as /atilde, and the likes of /daggerdbl, as well as ligatures such as that in [(Quinta do Bom) /fi (m)]. Most of the characters one might need are in the box on the right, or in /TimesNewRomanPS-BoldMT: accented characters and their PostScript glyphs. Others are listed in appendix E.5 of the PostScript Language Reference Manual, third edition; a still fuller list is at​papers/​trivia/​character-entities.html. (But most fonts do not contain all the glyphs listed, so check the output carefully.) Any string parameter may be replaced with an array of any of: strings; glyphs; other like arrays; and indeed pieces of PostScript code such as “{-0.06 Kern}”.

Non-compounded string
Non-compounded string

If using a compound string, do ensure that it has been compounded. The following type of error has been seen more than once (code below, example pictures on right).

/Circlearrays [  % First item erroneous.
	[ (1963)  (Graham) /quoteright (s)  ]  % Wrong! Missing [...] compounding.
	[ (1963) [(Graham) /quoteright (s)] ]  % Correct.
] def

The ‘wrong’ element of Circlearrays has four pieces (1963, Graham, and s), on the page separated by ≥ 3 spaces; whereas the correct version has two pieces (1963 and Graham’s), the second of which is a compound string.

Titles, Abovetitles, Belowtitles, Overtitles, Circlearrays

 Abovetitles and Overtitles

As well as Belowtitles, there are similar arrays Abovetitles and Overtitles. The diagram on the right shows the usage of these arrays. It is best if items of Titles are short, ideally ≤ 4 characters, so that they can be shown very large. Separately, observe that the Titles and Overtitles have been ‘filled’ with text: see FillTexts below.

This profusion of places to put information should be used sparsely, and consistently. For example, in a vertical, the Titles might contain two-digit years and the Overtitles the name of the shipper/quinta/château. Most Abovetitles would be blank, only a few specifying a non-standard bottle size (“Double Magnum”). Most Belowtitles would be blank, only a few specifying the likes of “Cask Sample”.

 Other Page Types

Much of this data is used to drive many other types of pages, including Tasting-note pages, Vote Recorder and Decanting Notes. But these lack the space to hold all the data that can fit in a glass-sized circle. Each has room for two sets of text analogous to the four title-type arrays, and one analogous to the Circlearrays. These are stored in arrays as follows.

On Glasses, Pre-Pour, Sticky Labels →

Page type ↓

Tasting NotesTitlesTastingNotesSubtitlesTastingNotesCirclearraysTastingNotes
Vote RecorderTitlesVoteRecorderSubtitlesVoteRecorderCirclearraysVoteRecorder
Decanting NotesTitlesDecantingNotesSubtitlesDecantingNotesCirclearraysDecantingNotes
Cork DisplayTitlesCorkDisplaySubtitlesCorkDisplayCirclearraysCorkDisplay
/Circlearrays [
	[ (1927) (Niepoort) ]
	[ (1931) (Niepoort) ]
	[ (1945) (Niepoort) ]
	[ (1955) (Niepoort) ]
	[ (1963) (Niepoort) ]
] def
/TitlesTastingNotes [ Circlearrays {0 get} forall ] def
/Titles [ TitlesTastingNotes {2 2 getinterval} forall ] def

These arrays may be set to already defined arrays, such as the default “/SubtitlesTastingNotes Belowtitles def”. Or they may be set to custom values, differing from one page type to the next. But all these arrays must be the same length.

Indeed, it is quite usual to generate variations automatically. For a vertical tasting, elegance is enhanced by having in the Titles two-digit years (“63”), but on the tasting-note sheets four-digit years (“1963”). The example on the right generates much of this automatically, and so repays study.

Similar variations are allowed for Names: NamesTastingNotes, NamesVoteRecorder, and NamesStickyLabels. There is also NamesPlaceNames, an array of Names-like arrays, so nested one deeper. These might be used to have “His Excellency The Ambassador” on glasses and tasting-note pages, “H.E. The Ambassador” on the more cramped place-name pages, and just “H.E.” on the very cramped vote-recorder pages. Indeed, there might be two place-name pages, one saying “H.E. The Ambassador” and the other saying “Roast beef”—discussed below.

 Other parameters


◊ The fonts in which the various text pieces are rendered are contained in the parameters NamesFont, CircletextFont, TitlesFont, AbovetitlesFont, BelowtitlesFont, OvertitlesFont, FillTextFont, SubtitlesFont (on non-glasses sheets), HeaderFont, FooterFont, and even the rarely-used BackgroundTextsGlassesFont.

But PostScript uses font names that are not always obvious. Help is at hand: distilling produces a PDF with a list of the available fonts, their PostScript names, and formatted example text. If distilling on a different machine or with a different program, a different set of fonts might be available: re-test by re-distilling

The program was designed for left-to-right script, and the alphabets successfully used have been Roman (mostly), Greek (occasionally), and Cyrillic (rarely). Users with knowledge of PostScript who are able to assist with testing in other scripts—including right-to-left—are invited to contact the the author, perhaps after reading this request for assistance rendering “泉十段”.

 PaperType and Orientation

◊ Two parameters control the page size and the page orientation:

/PaperType /A4 def  % /A4 /A3 /B4 /USL /USLegal /USL2 [SmallerPts LargerPts]
/Orientation /Portrait def  % /Landscape /Portrait


In PostScript sizes, distances, lengths, widths, etc, are always denominated in points, where 72 pt = 1″ = 1 inch = 25.4 mm, and hence 1 pt = 172″ = 0.01388″ = 127360 mm = 0.35277 mm, and 1 mm = 360127 pt ≈ 2.83 pt.

A useful ready reckoner is 6 mm ≈ 17 pt, this being inexact by only one part in 2159, as 6 mm = 171127 pt.

If using lots of measurements in millimetres, near the start of the file insert the line “/mm {360 mul 127 div} def”, which automatically converts the likes of “6 mm” (with a space) into Adobe points.

Angles are always in degrees = ° and never in radians, so a quarter turn is 90°. PostScript’s arithmetic is only single precision, so angles should not have magnitude larger than a few thousand degrees. I.e., prefer -40° to 5000°.

In the first line allowed values include /A4 (≈ 210mm×297mm, 8.28″×11.70″), /USL (8½″×11″), /A3 (≈ 297mm×420mm, 11.70″×16.55″), /USLegal (8½″×14″), /USL2 (11″×17″), or a custom page size expressed in points (see box on right) as an array of length two: [d1 d2] with 0 < d1 ≤ d2. For convenience of copy-pasting, some of the allowed values appear in the comment at the end of the line—after the “%”. Also allowed are sizes from /A9 (don’t ask why but do shrink the margins) to /A0, and from /B9 to /B0. In the second line allowed values are /Landscape and /Portrait.

Also see the separate manual page Glasses placemat: choosing a paper size.

Around the edge of the page is an invisible margin, the circles lying inside the area at least the margin away from the edge of the page. The margin equals the parameters MarginL (left), MarginR (right), MarginT (top), and MarginB (bottom), each defaulting to 30 points = 512″ ≈ 10.6 mm.

 Decorating the Titles

 Colour Schemes

By default, the Titles are black if the relevant item of Overtitles is empty, and grey otherwise. By default the Abovetitles and Belowtitles are always black; and Overtitles is black if the relevant item of Titles isn’t. These colour schemes are controlled by the parameters ColourSchemeTitles, ColourSchemeAbovetitles, ColourSchemeBelowtitles, ColourSchemeOvertitles, each of which can be set to (code evaluating to) /Black or /MidGrey. There is also the analogous parameter ColourSchemePlaceNames, used to control the colour of Place Names.

Example of CrossHatchingTitles


◊ The example on the right is filled with a check pattern. This check is activated by the boolean CrossHatchingTitles. The polar gridlines originate from a point with x coordinate CrossHatchingCentreX which can take values of /Name, /Left, /Center, /Right, or a number being points from the left edge of the page; and y coordinate CrossHatchingCentreY with possible values /Name, /Bottom, /Middle, /Top, or points from the bottom of the page. Lines are formatted and stroked by the code in CrossHatchingTitlesStrokeCode (the code must include the stroke, this requirement permitting the likes of “gsavestroke grestorestroke”). The number of straight lines is CrossHatchingNumRadialLines, defaulting to 180 so 2° apart. The radial gaps start at CrossHatchingRadialGapStart (this is the diameter of the inner-most circle), the gaps between the radii tending to CrossHatchingRadialGapAtInfinity with decay CrossHatchingRadialGapDecay. The author believes that CrossHatching… looks quite stylish when every item of Overtitles is empty, and hence the text in black and the lines defaulting to white.

There are analogous booleans CrossHatchingAbovetitles, CrossHatchingBelowtitles, CrossHatchingOvertitles, and CrossHatchingPlaceNames; and strokeing code CrossHatchingAbovetitlesStrokeCode, CrossHatchingBelowtitlesStrokeCode, and CrossHatchingOvertitlesStrokeCode (CrossHatchingPlaceNames uses the sub-parameters of CrossHatchingTitles). CrossHatchingBackground (with CrossHatchingBackgroundStrokeCode) controls whether (and how) the cross hatching appears in the background, filling the inside of the circle behind the various titles, and CrossHatchingBackgroundSuppressForDecanterLabels controls whether this is suppressed for decanter labels.

Example of outlined titles

 Stars and flowers

◊ In the very cluttered diagram on the left, showing QvA08, the Titles and Belowtitles contain small random stars and flowers. This feature is activated by setting to true the boolean parameter ShapesInTitles, which has obvious variations ShapesInAbovetitles, ShapesInBelowtitles, ShapesInOvertitles, and ShapesInPlaceNames. The array ShapesToUse, defaulting to [/Flower /Star], controls which shapes are used.

The shape is filled with the code ShapesTitlesFill (or ShapesAbovetitlesFill, +ShapesBelowtitlesFill, ShapesOvertitlesFill), which, if the shapes are filled, should end with a fill. The shape is then stroked with ShapesTitlesStroke (or ShapesAbovetitlesStroke, ShapesBelowtitlesStroke, ShapesOvertitlesStroke) which should end with a stroke.

For the stars, the numbers of points and the step between points are chosen randomly from within ShapesStarsPointsAndStepsArray, the default [[5 2] [6 2] [7 2] [7 3] [8 3]] being small 5/2 star small 6/2 star small 7/2 star small 7/3 star small 8/3 star. A possible alternative value for ShapesStarsPointsAndStepsArray is [[3 1.318] [4 1.792] [5 2.278] [6 2.77]], being pointier and less polygonal: small sharp 3-pointed star small sharp 4-pointed star small sharp 5-pointed star small sharp 6-pointed star. (Mathematicians might be interested in an open question about such stars.) For the flowers the number of petals is chosen randomly from ShapesFlowersNumPetalsMin to ShapesFlowersNumPetalsMax, and, as a proportion of 360° divided by the number of petals, the angular width of each is chosen randomly from the range ShapesFlowersAngularWidthMin to ShapesFlowersAngularWidthMax.

The radius of each shapes’s enclosing circle is random in the range ShapesEnclosingCircleRadiusMin to ShapesEnclosingCircleRadiusMax. An approximation to the typical separation between the shapes is ShapesAverageSeparation; a parameter controlling how far stars are moved from a regular grid is ShapesAverageMaxTweakPlusMinus.


◊ The Titles can be outlined by setting /OutlineTitles true def, as in the (still very cluttered) example with flowers and stars. The innermost white and black outlines have width OutlineTitlesInnerWidthWhite and OutlineTitlesInnerWidthBlack, and these widths grow in successive outlines by factors of OutlineTitlesMultiplierWhite (defaulting to ½(1+√5) = the golden ratio ≈ 1.618) and OutlineTitlesMultiplierBlack (defaulting to unity). The number of black ripples is capped at OutlineTitlesMaxNum.

If OutlineTitlesAlsoAbovetitles is true then Abovetitles are also outlined; if false then Abovetitles sit plainly atop the lines (and likewise OutlineTitlesAlsoBelowtitles and OutlineTitlesAlsoOvertitles). Generally it helps if the decanter labels fit onto a rectangular business card, so the default value of OutlineTitlesSuppressForDecanterLabels suppresses the outlines on the decanter labels. OutlineTitles does not impose as high a burden on a printer as does FillTexts, but can still be difficult for some. Again, test your printer.

Example of inlined titles


◊ A more architectural form of decoration is activated by the booleans InlineTitles, InlineAbovetitles, InlineBelowtitles, InlineOvertitles and InlinePlaceNames. These are in some sense a reversal of OutlineTitles—the lines being on the inside. In the Titles the lines have widths of InlineTitlesBlackWidth and InlineTitlesWhiteWidth; with obvious variations InlineAbovetitlesBlackWidth, InlineTitlesBlackWidth, InlineAbovetitlesWhiteWidth, InlineBelowtitlesBlackWidth, InlineBelowtitlesWhiteWidth, InlineOvertitlesBlackWidth and InlineOvertitlesWhiteWidth. All default to 1. If the colour scheme is /MidGrey then “black” means the darker of the two shades, and “white” the lighter.

The code can make an estimate of how many contours are needed, and does so if InlineTitlesAttemptMinimiseNumContours (or InlineAboveBelowOverAttemptMinimiseNumContours or InlinePlaceNamesAttemptMinimiseNumContours) is true. This estimate is then capped at InlineTitlesMaxNumberContours or InlineAbovetitlesMaxNumberContours or InlineBelowtitlesMaxNumberContours or InlineOvertitlesMaxNumberContours. (InlinePlaceNames uses the sb-parameters of InlineTitles.) If the code’s estimate is too low, as might happen if the lines are very thin, then the booleans should be false and the upper bounds set carefully. The attempted estimate is computed using a horrible algorithm, ‘discussed’ at comp.lang.postscript. By default the upper bounds are 1, which is elegantly sparse.


The example on the right is also at a jaunty angle (well, an angle that the author imagines might be jaunty). This is controlled by RotationTitlesAboveBelowOverCirclearray, which rotates the whole glass circle by that number of °, and is here set to 15.

Example of titles filled with text


◊ The booleans FillTitles, FillAbovetitles, FillBelowtitles, FillOvertitles, and FillPlaceNames control whether their respective elements are filled with multiple copies of some text, outlined. The filling texts are in the array FillTexts, which is of the same length as Titles, and each is outlined FillTextNumOutlines times. Depending on the values of ColourSchemeTitles etc, the colours are either black and white, or 40% grey and white. Each rendering of an item of FillTexts is suffixed with FillTextNumSpaces spaces.

The additional parameter FillTextAngle may be deffed to a number (30 being a good choice), this being the ° from horizontal at which the FillTexts are shown. Alternatively, FillTextAngle may be one of /LowerLeft, /LowerCenter, /LowerRight, /MiddleLeft, /MiddleCenter, /MiddleRight, /UpperLeft, /UpperCenter or /UpperRight such that the text will be 90° to a line drawn from the centre of the circle to that corner or edge or centre of the page. Or FillTextAngle may be /Name, making the angle perpendicular to a line drawn to the positioning of the Names.

The FillTexts are set in the font FillTextFont, at a size of at least FillTextMinFontSizeAbsolute, and of a size of at least FillTextMinFontSizeProportionLargestTitleAboveBelowOver × the largest their font sizes.

In the example on the right the relevant item of Titles is (S); of Overtitles is (Sandeman); of Circlearrays is [(Sandeman) (1985)]; of FillTexts is (1985), with FillTextNumSpaces being 2 and FillTextAngle being 30, and all the typefaces being /HelveticaNeue-CondensedBold. The default value of FillTextAngle is complicated, but natural. If GlassesOnSheets specifes a two-page layout, then to /LowerRight on the first sheet, and /LowerLeft on the second. If not a two-page layout, then if NamesAtTop is true to /LowerCenter, otherwise to /Name.

The formatting of the PlaceNames… generally matches that of the Titles, except that the filling text is FillTextPlaceNames, and the angle is FillTextAnglePlaceNames.

Use of FillTexts makes distillation slow, and produces files that can be too complicated for some printers. The balance between these two can be influenced by the boolean FillTextPrintQuickerDistillSlower. For example, in a draft placemat with FillTitles and PlaceNames, changing FillTextPrintQuickerDistillSlower from false to true decreased the file size from 1013k to 871k, but increased the distill time from 64 seconds to 40 minutes. If distilling the PostScript via the web the latter would definitely have timed out the browser. And it might be that, on some printers, the print-slowly option (false) won’t print at all, whereas the print-quickly option (true) will. But some printers can’t cope with either: the author’s Canon Pixma MP240 fails to print the FillTexts at all, the interior of the Titles rendering as plain white. (Printing this FillText test page to an MP240 results in output of which this scan is an extract.) But the author’s next printer, a Samsung ML-2955DW, did print successfully, but with insufficient resolution for the small grey text to look entirely satisfactory. So test your printer; do not assume that anything will work first time; and do not assume that all larger more expensive printers cope better.

It also appears that Adobe does not always distill or render perfectly these FillTexts. This problem can be fixed by opening the PostScript file with Preview on the Mac OS X, and then printing from Preview or saving the PDF file Preview makes and subsequently printing from Acrobat (technical demonstration of error).

But there is also a problem with Preview on the Mac OS X, which crashes if the paths are too complicated. The relevant constraint is on the complexity of the path of the item of FillTexts, plus the complexity of the path of the text that is filled (the item of Titles or of Names, as appropriate). As Names are typically longer than Titles, the problem can typically be remedied by setting PlaceNames to false.

 Page-level settings

The Names of people can appear at the top or bottom of each glasses sheet, or both or neither. Presence or absence is determined by two arrays of booleans, NamesShowTop and NamesShowBottom, each of the same length as GlassesOnSheets. The names are rendered in the font NamesFont, at a size equal to the size of the largest of the Circlearrays, subject to a minimum of NamesFontSizeMin and a maximum of NamesFontSizeMax.

If Rotate180AlternateNames is true then, for every other person, the glass and tasting-note pages are rotated 180°. At set-up time this slightly simplifies separation of pages by owner.

Example of use of Rays


To connect circles with pseudo-electrical field lines, as in the example on the left, set Rays to true. Then from each glass’s circle there emanates RaysLinesPerGlass lines, the first being offset from vertical by RaysAngleOffset°. It is recommended that RaysLinesPerGlass be an integer multiple of 4. The rays can be truncated at the margin, or at the edge of the paper, controlled by the boolean RaysLinesToPaperEdge. If this is true, it is even more important to ensure that printing is done at 100% with no scaling. Curves shorter than RaysMinLengthCurves are suppressed, though the ‘length’ is approximate, and includes parts that are outside the usable area and hence clipped. The formatting of the stroke can be controlled within RaysStrokeCode.

The electrical-ness is very pseudo. With real electro-magnetic lines, each circle would have to be of a positive or negative charge. So if A connected to B, and B to C, that would constrain the extent to which A could connect to C. But these lines can, layout dependent, connect any combination of pairs of circles. If a physical interpretation is wanted—this being strongly dis-recommended—it would have to be chromatic. It is best to deem the whole thing ‘decorative’. (Comment from a real physicist would be welcome.)

Examples Rays, a few tangled

Imperfections in the algorithm (discussion thereof) can cause aesthetically detrimental crossovers, as in three of the frames in the example on the right (24, 44, 64), in which the grey number is the value of RaysLinesPerGlass. Typically the problem can be fixed by tweaking RaysLinesPerGlass or RaysAngleOffset.


◊ Particularly at a tasting of a sweet fortified wine, drinking water is important. If WaterCounts is true, then there is a set of little glass icons (see lower-right of figure on left) with which to record water consumption: check one for each glass of water downed. Even better, use a diagonal slash (I drank half a glass of water) for a half glass of water, and a cross (I drank a whole glass of water) for a whole.

Example of watercounts

The boxes are arranged in a triangle with WaterCountNumSideTriangle on the lower edge, so the total number of boxes is typically this plus its square, halved. The boxes are no bigger than WaterCountSizeMax on each side, the gap÷box ratio being WaterCountGapProportionSize.

Boxes should appear on the lower-right of the page for right-handed drinkers, and lower-left for left-handers. Tasters’ handedness is set by LeftHanders, an array of the text of the name of known left-handers, whether or not at this tasting. If a name within Names is duplicated, and both are to be left-handed, that name must appear twice within LeftHanders.

If there are multiple pages of glasses (see GlassesOnSheets below), then on which of these pages should they appear? For simplicity, WaterCountsOverrideShowEverySheet overrides the complexity in the next few sentences, putting watercounts on every sheet. But if WaterCountsOverrideShowEverySheet is false, the presence or absence is controlled, for the right handers, by the array of booleans WaterCountShowRight; and for the lefties by WaterCountShowLeft. Nota Bene: WaterCountShowRight and WaterCountShowLeft must be the same length as GlassesOnSheets. The default values of WaterCountShowRight and WaterCountShowLeft refer to PageOrderingGlasses, which is implicitly assumed to specify sessions. Naturally enough, WaterCountShowRight defaults to true for the last page in each ‘session’, and WaterCountShowLeft for the first. logo on a cufflink

The majority of the placemats created by the author are for tastings arranged via To control the placement of a ThePortForum icon (examples on page at top, cufflink bearing logo on right), the parameter ThePortForumIconPlacement is set to one of /None, /LowerLeft, /LowerRight, /UpperLeft, /UpperRight, /LowerNonWaterCount, /UpperNonWaterCount or /UpperWaterCount, the last three evaluating to left or right according to the side on which the WaterCounts are placed. Alternatively, for multiple icons on the page, ThePortForumIconPlacement can be an array of any of the non-/None of these possibilities. Icons on the tasting-note pages are controlled by ThePortForumIconTastingNotePlacement, with permitted values /None, /LowerLeft, /LowerRight, /UpperLeft, /UpperRight, /LowerNonName, /UpperNonName and /UpperName. Whether or not the icons are shown in colour, small colour ThePortForum logo or small black-and-white ThePortForum logo, is set by the boolean ThePortForumIconColour.


The layout of the glasses is very flexible. The user specifies an array, PermittedPackingStyles, which is a list of packing styles, each style optionally having constraints (e.g., only if Orientation is /Landscape) and flags (e.g., /Mirror). One at a time each style from the list is taken, and each allowed variation is tested. Broadly, the one with the biggest radius is selected. Before describing details, let’s show some examples.

/Diamonds: circles in each row and column lie midway between those in neighbouring rows and columns.

4 glasses, /Diamonds on /A4 /Portrait
5 glasses, /Diamonds on /A4 /Portrait
13 glasses, /Diamonds on /A3 /Landscape
/USLegal (8½″×14″)
9 glasses, /Diamonds on /USLegal /Landscape
/USLegal (8½″×14″)9 glasses, /Diamonds /Mirror on /USLegal /Landscape
[ /Diamonds /Mirror ]

The first four of these specify the pattern with a simple a name, /Diamonds. Alternatively, one can specify a variant of the base style with an array, containing flag and constraints, such as [ /Diamonds /Mirror ]. In the array version, the first item of the array must be the base style.

/RectangularDislocation: The next four examples are rectangular, optionally with a horizontal ‘dislocation’ in the middle, that being, /Diamonds-style, circles lying between the circles in the adjacent row.

5 glasses, /RectangularDislocation on /A4 /Portrait
6 glasses, /RectangularDislocation on /A4 /Portrait
10 glasses, /RectangularDislocation on /A3 /Landscape
10 glasses, /RectangularDislocation /Mirror on /A3 /Landscape
[ /RectangularDislocation /Mirror ]

Again observe the /Mirror variant.

12 glasses, /SquareGrid on /A3 /Landscape

/SquareGrid: /SquareGrid can be similar to /RectangularDislocation. In the latter the glasses fill the page: observe the six-glass example above, in which the circles touch their vertical neighbours, but have a slight gap from the horizontal neighbour. In /SquareGrid there is no dislocation, and by default the vertical and horizontal distances are the same and equal to the diameter (example on right). /SquareGrid has two optional one-parameter flags: /HorizontalAlignment (which must have a value of one of /Left, /Right, /Centre, or /Justify); and /VerticalAlignment (one of /Top, /Bottom, /Middle, or /Justify). Obviously either /Justify can allow the horizontal and vertical distances to differ.

/DiamondsAndRectangular: For some numbers of glasses and aspect ratios, the best fit can come from a pattern that is a combination of /Diamonds and a rectangular pattern. The diamonds can be offset from the diamonds either vertically or horizontally.

Sometimes there are multiple ways to arrange the columns or rows: see the three examples of 14 glasses on A3. A sub-parameter can be set, /RectColsToLeftOrRowsBelow, which specifies the number of rectangular columns to the left of the diamonds, or the number of rectangular rows below the diamonds. The number is automatically pruned, so far-right can be specified with the likes of [ /DiamondsAndRectangular /RectColsToLeftOrRowsBelow 999 ]. By default the diamonds are put in the middle, if that is possible, otherwise at 0 ⇒ far left or bottom.

14 glasses, /DiamondsAndRectangular on /A3 /Landscape
14 glasses, /DiamondsAndRectangular on /A3 /Landscape
[ /DiamondsAndRectangular /RectColsToLeftOrRowsBelow 0 ]
14 glasses, /DiamondsAndRectangular on /A3 /Landscape
[ /DiamondsAndRectangular /RectColsToLeftOrRowsBelow 2 ]
/USL2 (11″×17″)
14 glasses, /DiamondsAndRectangular on /USL2 /Landscape
/USLegal (8½″×14″)
9 glasses, /DiamondsAndRectangular on /USLegal /Landscape

/RectangularAlternateNudge: In this third rectangular variant, alternate rows (or columns) are slightly nudged, better to fill the space.

12 glasses, /RectangularAlternateNudge on /A3 /Landscape

Thus /RectangularAlternateNudge is a small deviation away from greater symmetry, about which the the author is unenthusiastic. Because of this non-enthusiasm, by default, /RectangularAlternateNudge comes with a sub-parameter: [ /RectangularAlternateNudge /ImprovementPointsMin 2 ]. This imposes an additional requirement: choose this packing style only if it is an improvement on the previous best radius of ≥ 2 points ≈ 0.7 mm. The next four examples show six glasses on /USL = 8½″×11″ with 30 point margins, using the packing styles /Diamonds (radius ≈ 115.696); /SquareGrid and /RectangularDislocation (radius = 122); and /RectangularAlternateNudge (radius ≈ 124.102). So the radius improves by ≈ 2.102 pt, and hence the diameter by ≈ 1.5 mm. But on /A4 the improvement in the radius is much less: only 0.118 pt ≈ 0.04 mm, which seems insufficient to justify the asymmetry’s aesthetic damage.

/USL (8½″×11″)
6 glasses, /Diamonds on /USL /Portrait
radius ≈ 115.696
/USL (8½″×11″)
6 glasses, /SquareGrid on /USL /Portrait
radius = 122
/USL (8½″×11″)
6 glasses, /RectangularDislocation on /USL /Portrait
radius = 122
/USL (8½″×11″)
6 glasses, /RectangularAlternateNudge on /USL /Portrait
radius ≈ 124.102

/RectangularAlternateSplitNudge: This is a second ‘nudged’ rectangular variant, with the non-nudged rows (or columns) centred (or middled), and the nudged rows (etc) split, part nudged left (…) and part nudged right (). This works particularly well for twelve glasses on /USL2 = 11″×17″. In the two 12-glass examples below the rows are nudged; in the two 10-glass examples the columns are nudged. Note that /RectangularAlternateSplitNudge does not maximise the radius (obviously non-split nudging gives a larger radius) so for it to be used most other styles have to be removed from PermittedPackingStyles, or otherwise suppressed.

/USL2 (11″×17″)
12 glasses, /RectangularAlternateSplitNudge on /USL2 /Landscape
/USL2 (11″×17″)
12 glasses, [ /RectangularAlternateSplitNudge /Mirror ] on /USL2 /Landscape
[ /RectangularAlternateSplitNudge /Mirror ]
/USL2 (11″×17″)
10 glasses, /RectangularAlternateSplitNudge on /USL2 /Landscape
/USL2 (11″×17″)
10 glasses, [ /RectangularAlternateSplitNudge /Mirror ] on /USL2 /Landscape
[ /RectangularAlternateSplitNudge /Mirror ]

Both /RectangularAlternateSplitNudge and /RectangularAlternateNudge admit use of flags /ProhibitVerticalNudging or /ProhibitHorizontalNudging. Obviously using both would be strange.

7 glasses, /DiamondsPlus on /A4 /Portrait

/DiamondsPlus is mostly three-row diamonds (or, if /Portrait, three-column), with two extras set between the three rows (columns). It is the best packing of seven or ten glasses on several paper sizes.

There is a generalisation of /DiamondsPlus over any odd number of rows (columns), not yet coded.

/Arch and /PostsAndLintel: /PostsAndLintel arranges the circles around the left, top and right edges of the page, optionally with some circles at the bottom centre. This design might be particularly appropriate if the central circles held the candidate blends of a vintage, with some of the components around the edge. /Arch is similar, with the circles on a half ellipse.

(Technical note: for most patterns the radius and positions are computed analytically, to within PostScript’s single precision. There are two exceptions. For /DiamondsPlus, two quartic equations are solved numerically. For /Arch, the computation is an interval-bisection loop, containing a more complicated glass-positioning iteration. /Arch radii are believed correct to within 0.1 pt ≈ 0.035 mm, accurate enough for printing, but don’t use the radii as input to sensitive computations.)

The next four examples are specified as follows:

8 glasses, /PostsAndLintel on /A3 /Landscape
[ /PostsAndLintel /CentralGlasses 1 ]
7 glasses, /PostsAndLintel /Mirror on /A3 /Landscape
[ /PostsAndLintel /CentralGlasses 1 /Mirror ]
8 glasses, /Arch on /A3 /Landscape
[ /Arch /CentralGlasses 1 ]
10 glasses, /Arch on /A3 /Landscape
[ /Arch /CentralGlasses 3 /Mirror ]

The maximum number of /CentralGlasses is 3.

/Adjusted5 and /Adjusted7: Ignored for more than five and seven glasses, respectively.

5 glasses, /Adjusted5 on /A3 /Landscape
5 glasses, /Adjusted5 on /A3 /Landscape
[ /Adjusted5 /Mirror ]
/USLegal (8½″×14″)
7 glasses, /Adjusted7 on /USLegal /Landscape
/USLegal (8½″×14″)
7 glasses, /Adjusted7 on /USLegal /Landscape
[ /Adjusted7 /Mirror ]

This looks less good in /Portrait, so the default specifications are of the form [ /Adjusted5 /OnlyIfOrientation /Landscape ]. Self-evidently, the /OnlyIfOrientation causes the pattern to be ignored if the orientation is wrong.

There are also three simple designs, /TopRow, /MiddleRow, /BottomRow, each having everything in one row, with obvious vertical position. There is also /Sides, with the obvious meaning. For more than a few glasses these are too cramped.

4 glasses, /TopRow on /A3 /Landscape
4 glasses, /MiddleRow on /A3 /Landscape
4 glasses, /BottomRow on /A3 /Landscape
6 glasses, /Sides on /A3 /Landscape
[ /Array /Positions [0 2] [2 2 3 2] [4 2 3 2] [6 2] [0 1] [3 1] [6 1] [0 0] [3 0] [6 0] ] on /A3 /Landscape
[ /Array /Positions [0 2] [2 2 3 2] [4 2 3 2] [6 2] [0 1] [3 1] [6 1] [0 0] [3 0] [6 0] ]

Alternatively, PermittedPackingStyles may specify a layout with an array of coordinates. Such a specification is always an array, [ /Array/Positions … ].

After the /Positions marker is a list of points, typically of the form [x y], with y increasing up the page. The code then chooses the radius and separately scales the x and y directions such that things fit as snugly as possible, obviously subject to the other upper bounds on the radius. The glass ordering is that given in the array: there is no subsequent sorting or ordering.

There is a more complicated variant, in which some of the sub-arrays are of the form [x y xy]. The first two elements are used, as before, and fix the radius and the canvas. The circle at (x,y) is then moved in a straight line towards (x′,y′). A circle stops moving if it collides with another circle (a tangential touch not being a collision); if it collides with the edge of the page; or it arrives at (x′,y′).

As an example of unmoved and moved circles (inspired by a GC + SW + QH triple vertical in November 2011), the diagram on the right has two frames, the difference being the grey bolded numbers in [ /Array /Positions [0 2] [2 2 3 2] [4 2 3 2] [6 2] [0 1] [3 1] [6 1] [0 0] [3 0] [6 0] ]. For the author’s taste, the closer relationship of the two B0 circles means they should be touching, rather than equally spaced between A0 and C0.

There are other flags and constraints and sub-parameters, as follows.

 Radius bounds

When there are few glasses on a page, the radius of the circles could become very large. Hence the radius of the circles is bounded above by MaxRadius. Further, if there are multiple pages of glass sheets, it can look neater if all the pages, or all the pages in the same session, have the same radius. This is controlled by ShrinkRadii, which can be /NotAtAll, so each page’s radius is determined independently; /ToSmallest, so all pages have the same radius; or /ToSmallestSamePageOrdering, so the radius of each page in the same session, presumed to be equivalent to having the same value of PageOrderingGlasses, is shrunk to the smallest of that session’s radii. Alternatively, ShrinkRadii may be an array of the same length as GlassesOnSheets, pages being grouped if their array values are equal (so the default value of ShrinkRadii, “/ToSmallestSamePageOrdering”, is equivalent to “{PageOrderingGlasses}”).

Side-by-side, right-Handed
Side-by-side, left-Handed

 Side-by-side Glasses and TastingNotes

◊ If having a mini tasting of only three wines, one might wish to print everything on one sheet. For right handers the three glasses would be on the left of the tasting-notes; for lefties, glasses to the right—as in the images on the right. This small-tasting layout is enabled by setting the boolean constant SideBySideGlassesTastingNotes to true. Between the two sides of the paper is a gutter, an internal margin, of size SideBySideGlassesTastingNotesWidthGutter; the proportion of the page occupied by the glasses (from the edge of the paper to the middle of the gutter) being SideBySideGlassesTastingNotesProportionPageGlasses. The people are right-handed unless present in the array LeftHanders.

When SideBySideGlassesTastingNotes is true several of the tasting-note parameters are ignored, action being determined by the glasses equivalent. Ignored parameters include TastingNotesPaperType and TastingNotesOrientation; PageOrderingTastingNotePages; and MirrorPagesTastingNotePages.

 Tasting-note pages

◊ By default there are also tasting-note pages (controlled by GlassesOnTastingNotePages), these pages being of size TastingNotesPaperType and orientation TastingNotesOrientation. The tasting-note pages are lightly divided into columns, the number of columns and the column headings being determined by the array TastingNotesColumnHeadings, by default this being [ (Times) (Eye) (Nose) (Mouth) (Score) ] (the “Times” column being intended to hold the times of decanting and sampling). These column headings are rendered in the font NamesFont at size TastingNotesColumnHeadingsFontSize. The columns have widths proportionate to TastingNotesColumnRelativeWidths, an array of the same length as TastingNotesColumnHeadings. TastingNotesColumnStrokeCode formats and strokes the lines that separate the columns.

The elements of TitlesTastingNotes are shown at a size not exceeding TastingNotesTitlesFontSizeMax, and the elements of SubtitlesTastingNotes are shown at TastingNotesSubtitleFontSizeProportionTitles times the size of the TitlesTastingNotes. The vertical separation between the CirclearraysTastingNotes and TitlesTastingNotes, and between the TitlesTastingNotes and SubtitlesTastingNotes, is TastingNotesLineGap.

	(JDAW) 5 1 /Alternating
	(DRT) 5 1 /Upright
] def
TastingNotesStarsNameColsRowsArrangement, /Alternating
TastingNotesStarsNameColsRowsArrangement, /Sideways
TastingNotesStarsNameColsRowsArrangement, /Upright

Optionally, there can be a row of stars: circle to score. This can nudge those not prone to scoring into doing so. But different people use different scoring systems, so the parameter TastingNotesStarsNameColsRowsArrangement determines things by name.

This is an array of length a multiple of 4. The first of each set of four is the text of the name of the person to whom this applies (before comparing the code removes non-text). The second is a number of columns; the third a number of rows. The fourth of each set of four is /Alternating or /Sideways or /Upright.


There is also the decorative boolean TastingNotesCirclesBehind, which repeats the elements from the glasses pages, faded by a factor of either TastingNotesCirclesBehindFadingFactorIfAnyGrey or TastingNotesCirclesBehindFadingFactorIfAllBlack, according to whether ColourSchemeTitles is ever /MidGrey. By default TastingNotesCirclesBehind is true if distilling with Distiller, false otherwise (because of an awkward technical bug in GhostScript). The circles are in a straight line, the x position at the top being TastingNotesCirclesBehindTopX (0 ⇒ left, 1 ⇒ right), and at the bottom is TastingNotesCirclesBehindBottomX. The complication of the default values causes, over multiple TN pages, some variation to the visual effect. The boolean TastingNotesCirclesBehindFitAndCentreInRow controls whether the circles fit between the horizontal lines made by the Circlearrays (true), or whether they are as large as possible (false).

There has been discussion of printing A6 booklets to hold the tasting-note pages, one wine per page. To aid this it is possible to replace the names with page numbers via TastingNotesReplaceNameWithPageNum, the page-number string being defined in TastingNotesPageNumCompoundString, and being shown in a font size reduced by a factor of TastingNotesPageNumFontSizeFactor.

Example of a place-name sheet

 Place Names

◊ At a large formal tasting it is appropriate to label each person’s place-setting, so everybody knows who everybody else is, even late in the tasting. Pages to facilitate this are produced using the boolean PlaceNames parameter.

The pages are formatted to match the Titles: example on the right.

There can be multiple copies of the place names, with different names, so NamesPlaceNames is an array of arrays of names, by default containing just one sub-array, Names. Why the multiple sets of names. Have one set with the names of the people, over—so hiding—the set with names of foods. When the food is about to arrive, switch them, so that waiters and waitresses see which plates go where. That done, switch back. This might be achieved with parameters resembling the following:

/Names [ (Alex) (Ben) (Chris) (Derek) ] def
/NamesPlaceNames [
	Names  % People
		(Steak & kidney pie)  % Alex
		(Filet, medium-rare)  % Ben
		(Roast beef, lots)  % Chris
		(Low-salt diet salad)  % Derek
	]  % Foods, and food-free foods
] def

There is also the parameter PlaceNamesShowNameAsFooter, an array of booleans the same length as NamesPlaceNames, controlling whether the relevant element of Names is to be shown as a footer. If the big writing says “Low-salt diet salad”, it can simplify set-up to have a very small “Derek” written on the page.

Pages require three folds. First, fold in half; then fold and press hard along the faint dashed lines, thereby preventing the corners curling. The side with the small-writing header and footer should face the named person; the side without should face away. Whilst these are being rendered TypeOfPagesBeingRendered is /PlaceName, and the variable PlaceNameSetNum is the number of the item of NamesPlaceNames.

These place-name pages are set on pages of size PlaceNamesPaperType (defaulting to TastingNotesPaperType), and orientation PlaceNamesOrientation (default /Landscape). The lines marking the anti-curling folds are a distance PlaceNamesFirstAndThirdFoldsFromEdge away from the top and bottom edges, defaulting to 36 = ½″ = 12.7mm, which should be changed to 0 if printing to stiff card. The Names are set in font PlaceNamesFont (defaulting to NamesFont, though sometimes TitlesFont would be more appropriate), at the largest size that fits subject to an upper bound of PlaceNamesMaxFontSizeAbsolute (defaulting to 192). The colour scheme used is ColourSchemePlaceNames, this functioning in the same manner as ColourSchemeTitles. Because these names are usually larger than the Titles, various details such as line-widths are set larger by a factor of PlaceNamesDetailsScalingFactor; but, messily, this parameter is used partly in the code, and partly in the default values of other parameters.

Caution: if used with FillTitles distillation is excruciatingly slow. Distillation over the web will almost certainly time out: use local conversion.

A pre-pour sheet

A pre-pour page from a Ramos Pinto vertical on 21 October 2014. The grey lines are the top-left of the “RP” BackgroundTextsGlassesTexts, with BackgroundTextsPrePourRefit deffed to false.

 Pre-Pour Sheets

◊ Tastings arranged on ThePortForum are for a maximum of fourteen people, in order to give a 5cl portion to each person (75cl bottle, less the angels’ share and less a little loss during decanting leaves only an edge more than 14×5cl = 70cl). At a tasting attended by eight people, decanters can circulate and people help themselves. But when there are fourteen people and so only 5cl each, portions need to be pre-poured. This could be a source of confusion: “What did you pour into these fourteen glasses?”, “Err, I think…”. Instead glasses are arranged on or close to a page that labels them. Then the pourer knows what to pour; and those moving the glasses to the table know what has been poured.

The number of copies of these pre-pour sheets is PrePourNumCopies, by default 0. If pre-pour sheets are wanted this should be set to a higher value: usually /PrePourNumCopies 1 def is sufficient, and 2 would allow for an awkward working space.

The ordering of the loops is controlled by PrePourCollate: if true then PrePourNumCopies is outside SheetNum and WithinPage/WithinTitles; if false then PrePourNumCopies is inside. In a typical vertical tastings, the oldest wines come first in the list, so as to be top-left of the sheet. But decanting is in the reverse order, youngest to oldest, so it is convenient to reverse the order of the pre-pour sheets. This is controlled by PrePourReverseOrder, which defaults to true. There are also obvious parameters PrePourPaperType and PrePourOrientation.

If RotationTitlesAboveBelowOverCirclearray ≠ 0, then small arrows appear on the pre-pour sheets indicating the correct orientation.

Example of a tasting in which over-lapping pages caused problems with the pre-pour sheets

This was constructed from two sheets of A3 card, both of which included the ’63 and ’83. The right sheet was guillotined (shown green), overlapped on the left, and fixed with double-sided sticky tape. The double-presence of the ’63 and ’83 caused them to have two pre-pour sheets, a problem later fixed by PrePourRemoveDuplicatesByWithinTitles. Also observe use of HeaderFooterCenterX.

For some layouts, it may be desirable for a specific bottle to appear on more than one glasses sheet (e.g. when using overlapping sheets). The consequent duplication of pre-pour sheets is removed by PrePourRemoveDuplicatesByWithinTitles being true, its default value. The guillotine-and-overlap trick also messes with the order of the pre-pour sheets, sometimes fixable with PrePourSortByWithinTitles.

To make pre-pour sheets for wines not appearing on a glasses sheet, see GlassesNumCopies.

 Points: The Vote Recorder

◊ At the end of a tasting there is typically a vote for the Wine Of The Night (WOTN), and for large tastings there might also be a vote after each flight or page. The vote is not usually secret, people being asked to declare 1st, 2nd, and 3rd places (scoring 3, 2, 1). To assist the ‘returning officer’ there is paper on which votes can be recorded. For WOTN it is the points that should be recorded, rather than the ranks, as doing so simplifies the addition of the totals. (There is also benefit in there being agreement as to what is recorded: if you record, but I retain the vote-recorder sheet and enter it into a description of the tasting, it is useful that “3” be unambiguously first place three points.)

Indeed, at tastings, the rules are slightly more liberal. Each voter has 6 points to assign, which may be assigned in any simple fractions, subject to no one wine receiving more than 3. So permitted scoring patterns include the likes of 3:2:1, and 3:3, and 2:2:2, and 3:1½:1½, and 2:1½:1:½:½:½, and others.

Vote recorder sheets can also be used to hold, in a blind tasting, guesstimates of which is what.

These sheets are enabled by setting VoteRecorders to true. There are then conceptually two levels of loops. Pages are specified, except the question in the top text. Then each of these pages can be re-used with multiple top texts.

The vote-recorder sheet contains the wines within GlassesClusteredOnVoteRecorders, which is a triple-depth array, so one deeper than GlassesOnTastingNotePages. The outermost array is one per vote-recorder page: voting on separate days, with different people or wines, or different total-column-row flags, should be recorded on separate sheets. Within this are ‘clusters’, intended to align with tasting-note pages. Within this are integers pointing to wines. The default value is empty if GlassesOnTastingNotePages is empty, otherwise [GlassesOnTastingNotePages], so the cluster divisions (some 25% grey backgrounding) on the vote recorder are page divisions between the tasting-note pages.

Example of VoteRecorderCrossedBox.

Of the same length as GlassesClusteredOnVoteRecorders is VoteRecorderTopTexts, a double-depth array. The inner arrays hold the one/multiple top-texts to be used with each item of GlassesClusteredOnVoteRecorders. There are also arrays of booleans VoteRecorderShowTotalRow and VoteRecorderShowTotalCol, which specify whether there is to be a total column or row. Generally a total column is always wanted; typically a total row is wanted only for blind-tasting “What is it?” top-texts. The (Total) strings are in VoteRecorderTotalColTitle and VoteRecorderTotalRowTitle: there might be changes for Kernning or different languages. For blind-tasting “What is it?” voting, typically the person who brought a bottle should not guess. Rectangles can be crossed out by setting VoteRecorderCrossedBox to code evaluating to a boolean, that code typically referring to WithinTitles and NameNum.

VoteRecorderNamesOrientation controls the orientation of the NamesVoteRecorder, with allowed values /Horizontal, /Vertical, or the default value of /Either.

Also ∃ obvious parameters VoteRecorderPaperType and VoteRecorderOrientation; and VoteRecorderTitlesFontSizeMax and VoteRecorderSubtitleFontSizeProportionTitles.

 Decanting Notes

◊ Those decanting should record the time each bottle is decanted, as well as the condition of the cork and perhaps the qualities of the sediment. Pages to do same are controlled by GlassesClusteredOnDecantingNotes, which has the same structure as GlassesClusteredOnVoteRecorders. There are DecantingNotesNumCopies copies of each page specified by GlassesClusteredOnDecantingNotes. Each page is headed DecantingNotesTopText, the columns being headed DecantingNotesColumnHeadingTimes and DecantingNotesColumnHeadingNotes. Other parameters specify page size and orientation, name the page, the columns, and DecantingNotesSubtitleFontSizeProportionTitles is analogous to VoteRecorderSubtitleFontSizeProportionTitles.

Also ∃ obvious parameters DecantingNotesPaperType and DecantingNotesOrientation, and DecantingNotesTitlesFontSizeMax and DecantingNotesSubtitleFontSizeProportionTitles.

Example of a cork-display page.

 Cork Display

Bottles having been decanted, corks should be put on display, for which pages are activated by /CorkDisplay true def. There are CorkDisplayNumCopies of each, and also CorkDisplaySpaceForNumExtras blanks for extra bottles that might appear. Each rectangle is at least CorkDisplayMinWidth wide, and at least CorkDisplayMinHeight high; and the corks shown are in GlassesClusteredOnCorkDisplay, a triple-depth array resembling GlassesClusteredOnVoteRecorders. Pages are titled with CorkDisplayTopText, defaulting to “The Corks”. The paper type is CorkDisplayPaperType; the orientation being chosen automatically.

 Decanter labels

The making of decanter labels is controlled by the integer DecanterLabelsNumCopies. Decanter labels are to fit within a rectangle of size DecanterLabelsMaxSmallerDimension × DecanterLabelsMaxLargerDimension (which should be the size of business cards less a small margin). The decanter label pages include instructions along the lines of “Decanter labels: cut; paste to business cards; allow to dry; punch holes; hang on decanters; fill decanters; wait; drink.” Two sets of decanter labels can be pasted to both sides of the business cards, sometimes affording those sitting ‘behind’ the labels a clue as to contents.

 Sticky labels

What is the purpose of the sticky labels that isn’t handled by the decanter labels?

At the start of decanting, some bottles will be clearly labelled. Others might have little more than a capsule, so after opening, could be entirely unlabelled. To prevent confusion there should be, printed onto sheets of sticky labels, bottle labels. Alternatively, in an informal tasting, with many more wines than glasses, it can be useful to stick to the foot of the glass (please, never the bowl, always the foot) a very small sticky label identifying the current contents and the glass’s owner. Specifying these requires describing the sheet of labels

Sticky labels appear if StickyLabelsNumCopies exceeds zero, and multiple copies are permitted. If the labels are for bottles, there is one per wine. If for glasses, there is one per wine per element of Names. StickyLabelsByNameWhichReplaceCirclearrays controls which; if there is one label per wine per person, then the element of Circlearrays is replaced with the element of Names. When there are labels by name, it is convenient for cutting if each name’s labels are in a convenient rectangular block, enforced by StickyLabelsAvoidAcrossColumnsOrRows, and not spilling over page boundaries, enforced by StickyLabelsAvoidAcrossPages.

To allow both bottle and glass labels, the sticky labels can be of multiple types, as contained in the array StickyLabelsTypes. This does very little: the sticky label code is run with StickyLabelsTypeThis set to each element of this in turn. The other parameters might choose to access the current value of StickyLabelsTypeThis. With StickyLabelsTypeThis equalling 0 the default parameters fit Ryman product 0220013460 (containing 25 sheets, or equivalently to the 100-sheet pack 0220023460), having on each A4 sheet eight labels, each 99mm×68mm. With StickyLabelsTypeThis equalling 1 the default parameters fit Avery J8651, each sheet of which has 65 labels, each 38.1mm×21.2mm. Regular users of this software should inform the author if other sheets of labels should be included in the defaults.

If not using a default, the user must change the specification of the label layout. For all the following it is assumed that the page is portrait.

Then StickyLabelsOrientation is the desired orientation of the labels. That is not necessarily the same as the orientation of the page: if, with the page held portrait, labels are wider than they are high, it will be the opposite. Allowed values are /Landscape and /Portrait. If StickyLabelsOrientationAutomatic then StickyLabelsOrientation is ignored, the orientation being chosen automatically, the code choosing /Landscape unless switching to /Portrait would increase the linear size of the text by ≥√√2.

If one has a part-used sheet of labels, it can help to specify the where on the first page of sticky labels to start, as if StickyLabelsFirstPageStartPosition had already been done.

To make sticky labels for wines not appearing on a glasses sheet, see GlassesNumCopies.

There are also settings StickyLabelsReverseOrder, StickyLabelsRemoveDuplicatesByWithinTitles, StickyLabelsSortByWithinTitles, StickyLabelsShowBackgroundTexts, and StickyLabelsShowCirclearraysInCircle (as well as in the straight lines top and bottom). These are analogous to the similarly-named PrePour… settings.

 Non-easy parameters

Stylised glasses sheet, 1 of 2 Stylised glasses sheet, 2 of 2

 GlassesOnSheets and GlassesOnTastingNotePages

◊ Imagine that ten wines are to be tasted—too many for one sheet of /A4 or /USL. So instead the glasses could be split over two sheets, as shown on the right.

This is done using the parameter GlassesOnSheets, which is an array of arrays, each of the inner arrays listing the elements of Titles etc to be on that page. This two-sheet example happens with GlassesOnSheets set to [   [ 0 1 2 3 4 ]   [ 5 6 7 8 9 ]   ], which is the default with Titles of length ten. Observe that numbering starts at 0: the first wine (described by the first element of each of Titles, Subitles, Circlearrays, and FillTexts) is number 0; the tenth glass is therefore number 9.

In the picture the WaterCounts are on the right side of the second page—as the author is right-handed. Participants are right-handed unless in LeftHanders, an array of the names of known left-handers. Which pages have water counts is controlled by WaterCountShowRight and WaterCountShowLeft. These parameters are described in the section on WaterCounts.

GlassesOnSheets has a more general purpose. As a putative tasting is being arranged, there are candidate bottles, some of which will appear in the final version. Create entries in Titles, Subitles, Circlearrays, and FillTexts for all these wines. Then, when decisions have been taken, use GlassesOnSheets to select from them, and to determine which wines appear in which order on which sheets.

The default value of /GlassesOnSheets is complicated. Let n = the length of Titles. Then if n ≤ 6, GlassesOnSheets is [ [0 1 2 … n–1] ], so putting all the glasses on a single page. Otherwise there are ⌈n ÷ 6⌉ pages, the glasses being distributed as evenly as possible, so each page holding ≤ 6. By default, GlassesOnSheets is the minimum number of pages subject to there being at most GlassesOnSheetsMaxPerSheet per page. The default value of GlassesOnSheetsMaxPerSheet can be 6 (if PaperType is /A4 or /USL) or 9 (/USLegal) or 14 (/A3 or /USL2).

The parameter GlassesOnTastingNotePages works the same way, controlling the tasting-note pages. By default it is built analgously to GlassesOnSheets, except from GlassesOnSheetsMaxPerTNSheet.

 Type sizes

How big is the circle text? In points, not bigger than CircletextMaxFontSizeAbsolute; and as a proportion of the circles’ radius not bigger than CircletextMaxFontSizeProportionRadius. If, in a font size equal to the lesser of these two, a particular item in Circlearrays is too long to fit at least CircletextsMinCopies times, then the font size is reduced such that it does. If CircletextsSameFontSizeIfRadiiShrunkToBeSame, then across all pages compelled to have the same radius (see ShrinkRadii), the Circlearrays are compelled to have the same size. If not, the font size of Circlearrays can vary within and between pages. (Technical note: CircletextsSameFontSizeIfRadiiShrunkToBeSame should have the same boolean value over any such set of pages. Typically this is most easily achieved by having it depend on PageOrderingGlasses SheetNum get or on ShrinkRadii SheetNum get, rather than directly on SheetNum.)

Imagine that, at the font size chosen in the previous paragraph, some particular item of Circlearrays fits 3.999 times, and so would be shown 3 times, with white space occupying the ‘0.999’ remainder. Aesthetically it would be better if the font size were tweaked a mite smaller, this item then fitting 4+ε times and being shown 4 times. The boolean parameter CircletextsTweakSize activates this tweaking. And if the boolean CircletextMaxFontSizeMayBeSlightlyExceeded is true, then there can be an initial tweak upwards in size (not exceeding a factor of √√2 ≈ 1.189). But if the user needs precise control over the font size (but why?), then both should be changed to false.

If Rays is activated, then CircletextsTryToResonateWithRays can improve the look of a very short item of Circlearrays, such as [ /dagger ] = “†”. The number of copies is also bounded above by CircletextsMaxCopies; when this is invoked the the number of copies that would otherwise appear is on the top of the stack, so CircletextsMaxCopies could be code referring to it, such code advisedly starting with a “dup”. Relatedly, the minimum separation between the items of the sub-arrays of Circlearrays, measured in space-widths, is CircletextsMinNumSpacesBetween.

The type sizes of Titles and Abovetitles, Belowtitles and Overtitles are controlled by a multi-stage process.

First, the Titles are fitted, and various one-at-a-time constraints applied. These include:

TitleMaxHeightProportionInnerRadius is the maximum height, measured bottom to top, of the Titles, expressed as a proportion of the ‘inner radius’, that is, of the radius to the inside of the Circlearrays, adjusted by ExclusionAnnulusProportionInnerRadiusTitlesAboveBelow.

TitleMinHeightForAbovetitleProportionInnerRadius: constrains the upper bound of the title if the relevant element of Abovetitles is non-empty.

TitleMinHeightForBelowtitleProportionInnerRadius: constrains the lower bound of the title if the relevant element of Belowtitles is non-empty.

For these purposes, “the circle” is the inside of the Circlearrays, adjusted by ExclusionAnnulusProportionInnerRadiusTitlesAboveBelow (for the Titles, Abovetitles and Belowtitles) or by ExclusionAnnulusProportionInnerRadiusOvertitles (for just the Overtitles). These might behave weirdly if negative or ≥1, and default to zero which uses all available space.

Second, the font sizes of the Titles are considered together. It would look messy if there were many type sizes, only slightly different. If FontSizesTitlesNotSmallerIfTitlesNotLonger true, then sizes are so constrained. I.e., the font size of “Df” must be ≤ the font size of “W” which must = that of “I”. Then a constraint is applied to their ratio: for two titles, either they have the same font size, or the larger÷smaller ratio of their font sizes ≥ FontSizesRatioTitlesMin, which defaults to 2.

Except that one might not wish to apply this constraint over pages in different sessions: it would hardly matter whether yesterday’s sheets did or did not precisely match today’s. So there is an array FontSizesSetsGlassesPages of the same length as GlassesOnSheets, and pages with matching values in this array are considered together.

Third, Abovetitles, Belowtitles and Overtitles are fitted around the Titles. Then, if needed, these are lowered to the size of the matching element of Titles, times AbovetitleMaxFontSizeProportionTitles, BelowtitleMaxFontSizeProportionTitles or OvertitleMaxFontSizeProportionTitles.

Fourth, as with the Titles, fewer matching font sizes would look better.

○ If FontSizesAboveBelowOverNotSmallerIfTitlesNotLonger, then, in turn and separately for each of Abovetitles, Belowtitles and Overtitles, lengths are constrained according to the lengths of the elements of Titles.

○ It is possible to force items to be the shown at the same font size. FontSizesTitlesEquivalences is an array of the same length as Titles. If two items of FontSizesTitlesEquivalences are equal, then the relevant Titles are forced to the size of the smaller. Likewise FontSizesAbovetitlesEquivalences for the Abovetitles, and FontSizesBelowtitlesEquivalences for the Belowtitles, and FontSizesOvertitlesEquivalences for the Overtitles. (But be careful: FontSizesTitlesEquivalences and FontSizesAboveBelowOverNotSmallerIfTitlesNotLonger together can force everything to the same size: if a short title is forced to be the same size as a long title, then every other title longer than the short title would also be forced to the same size.)

○ Then the ratio of FontSizesRatioAboveBelowOverMin is used, and over the same FontSizesSetsGlassesPages sets of pages.

But should Abovetitles be considered with Overtitles? If their fonts are very different, perhaps not. So there is an array of length three, FontSizesSetsAboveBelowOver, the elements of which refer to ‘Above’, ‘Below’ and ‘Over’, in that order. If the elements of FontSizesSetsAboveBelowOver are equal, the arrays are considered jointly. Typically, arrays in the same or similar fonts should be considered together; those in very different fonts should not.


BackgroundTextsGlasses: some 1982s BackgroundTextsGlasses: some 1983s    BackgroundTextsGlasses: more 1982s BackgroundTextsGlasses: more 1983s

In some multi-page tastings, for each page all the wines have something in common. A typical example is a multi-horizontal, in which wines from several houses are tasted from two or few vintages. As everything on a page has a common feature, perhaps this common feature should be marked, faintly, as in the two-session four-page example on the right.

This is activated by setting BackgroundTextsGlasses to true. Then BackgroundTextsGlassesTexts is an array of the same length as GlassesOnSheets, containing the strings to be shown. The strings should be short: one or two characters is recommended, and are shown in font BackgroundTextsGlassesFont.

The text is shown in the centre of the page, the separate x and y sizes each as large as possible, subject to the following.

The bounding path of the text is constructed and then BackgroundTextsGlassesPaintCode is executed. The default clips then strokes, but the example above shows a plain fill.

The boolean parameter BackgroundTextsTastingNotes also shows these on the tasting-note pages. For each such page, if every glass on the page appears on a glasses page with the same BackgroundTextsGlassesTexts, then that item is shown on the page. For pre-pour pages, which are naturally associated with a glasses page, the boolean BackgroundTextsPrePour causes the BackgroundTextsGlassesTexts to appear. Either this happens with only the appropriate part of the background text being visible, or, BackgroundTextsPrePourRefit, re-fitted to the pre-pour page.

 Separating flights within a page

[   [ [/Left 0 3 -0.5] [0 3] [/Top 3 0 +0.5] ]   [ [/Left 5 +1.0] [/Clockwise 5] [/Bottom 5 +1.0] ]   [ [/Bottom 3] /Curve [3 6] /Curve [3 1] /Curve [/Top 3] ]   [ [/Top 4] [1 4] [/Widdershins 4] [/Bottom 4] ]   [ /Closed [/Right] [/Bottom] [/Clockwise 7] [/Widdershins 4] [/Clockwise 2] ]   ]
[ /Closed [0 3] [3 1] /Curve [1 4] [4 2] [4 7] /Curve  [4 6] [/Widdershins 6] [6 3] /Curve [3 5] ]

◊ It is often natural to split a tasting into ‘flights’ of a few wines. This can structure a balance between quietly contemplating the differences between wines, and subsequent sociable discussion. The parameters FlightSeparations and FlightSeparationLines allow the page to be divided into zones. However FlightSeparationLines is fiddly, and if one wine is added or taken away, will need to be completely reworked. Hence it is recommended that division into flights be saved until late in the planning.

FlightSeparations is a boolean: true to activate the line-drawing code, false de-activated. The real work is done by FlightSeparationLines, being an array nested four deep. FlightSeparationLines is of the same length as GlassesOnSheets. Each item of FlightSeparationLines is an array, each of which holds line descriptions, as many as there are lines on that page. Each line description is an array, pieces of which can be as follows.

In the PDF of examples the header shows that page’s item of FlightSeparationLines (i.e., FlightSeparationLines is an array one deeper than the header). If using FlightSeparations it is strongly recommended that these PDF examples be examined and appropriate parts used as a starting draft. The first two pages of this file are shown on the right, the first having many example lines, to the gain of instruction and the loss of aesthetics.

The path can be stroked, clipped or filled by the code FlightSeparationPaintCode, which has a default stroke that is complicated but elegant. Use of fill is discouraged, as it impedes comparison of colours of the wines. If FlightSeparationPaintSeparately then FlightSeparationPaintCode is invoked after each line, the variable FlightSeparationLineNum being set to the appropriate integer ≥ 0. If not FlightSeparationPaintSeparately, then all the lines on the current page are drawn, after which is the single call of FlightSeparationPaintCode. The former is better if the format is not constant; the latter preferred if overlapping or crossing lines are to be double-stroked.

Some control over the radius of the arcs is sometimes possible. If any circles touch, the radius of the arcs equals that of the circles. If no circles touch (probably because of MaxRadius or ShrinkRadii) then FlightSeparationArcRadiusControl controls the radius. FlightSeparationArcRadiusControl should be both ≥0 and ≤1; the default being the maximum. If it is 0, the radius of the arcs is that of the circles. If 1, the radius is the half the distance between the closest circles. If between, between.

The 1997 Horizontal on 16th June 2014 had complicated usage of FlightSeparationLines, as can be seen from the following explanatory diagram. Some text nudged to keep it on the page, most obviously that referring to the corners.)

Example of complicated usage of FlightSeparationLines.

 Page order

◊ The order of the pages is controlled by eight arrays of integers.

Array nameLengthDefault
Default explained
PageOrderingGlassessame as GlassesOnSheets1 Sorted into order by the algorithm: in the outermost loop, by paper size. Within that, for simplicity of table setting, starting with interleaved glasses sheets and tasting-note sheets; then the vote-recording page(s) to be placed with the returning officer’s tasting-note sheets; then decanting-notes, cork display and pre-pour pages.
PageOrderingTastingNotePagessame as GlassesOnTastingNotePages1
PageOrderingVoteRecordersame as GlassesClusteredOnVoteRecorders1
PageOrderingDecantingNotessame as GlassesClusteredOnDecantingNotes1
PageOrderingCorkDisplaysame as GlassesClusteredOnCorkDisplay1
PageOrderingPrePourPagessame as GlassesOnSheets1
PageOrderingPlaceNamessame as NamesPlaceNames100Separated from 1s to facilitate pre-tasting folding.
PageOrderingDecanterLabelssame as GlassesOnSheets200Separated from above to facilitate pre-tasting gluing.
PageOrderingStickyLabelssame as GlassesOnSheets300Separated from above so there is a single switch of printer paper to the labels.

Draws are resolved in a manner that separates pages on different paper types, perhaps simplifing printer loading, as described by the following algorithm (in which “matching” means matching the page ordering and the paper type).

For a tasting over multiple sessions it can be helpful to have a page order more complicated than the default. For example, imagine a tasting split over afternoon and evening sessions, each session having three glasses pages and two tasting-note pages per person (example of such a tasting, inspiring but pre-dating these page-order controls). Managing such a tasting will be enough work and spare on the day: simplifying the task of table setting, thus reducing the likelihood of error, is worthwhile. One might set:

/PageOrderingGlasses [ 10 10 10  20 20 20 ] def
/PageOrderingTastingNotePages [ 10 10  20 20 ] def
/PageOrderingVoteRecorder  [ 10 ] def
/PageOrderingDecantingNotes  [ 10 20 ] def
/PageOrderingCorkDisplay  [ 10 20 ] def
/PageOrderingPrePourPages [ 10 10 10  20 20 20 ] def
/PageOrderingPlaceNames [ 1 2 ] def
/PageOrderingDecanterLabels [ 0 0 0  0 0 0 ] def
/PageOrderingStickyLabels [ 65535 65535 65535  65535 65535 65535 ] def

First out of the printer are the decanter labels, which can be cut and pasted to business cards in advance (integer: 0). Next are place-name pages for the two sessions, collated, to be folded before the day (1 and 2). Next are the glasses and tasting-note pages for the afternoon, with each person’s five pages together (10), followed by the vote recorder for the day (10), and the decanting-notes and pre-pour sheets for that session (10). Then the glasses and tasting-note pages for the evening, with each person’s five pages together (20) followed by decanting-notes, cork-display and pre-pour sheets (20). Finally the bottle labels at the end (65535) for ease of paper-changing in the printer.

The values in PageOrderingGlasses are used by ShrinkRadii as they are presumed to define sessions. The values in PageOrderingGlasses are also used to determine the default values of WaterCountShowRight and WaterCountShowLeft.

Example Table of contents

The sections can be lightly titled. The parameter PageOrderingSections is an array of even length, alternately items of the page orderings and compound strings, that adds extra rows to the PDF reader’s table of contents. The compound strings appear before the page orderings with which they are paired. On the right is an extract from a screen image, taken from a Mac’s PDF reader, Preview. The pinked regions (highlighted here for clarity but not in the actual PDF) were added with the following—do observe the separate addition of the empty lines. Alas Mac Preview, at least up to version 7.0 (826), ignores a little of the formating, as illustrated on the Apple Support Communities.

/PageOrderingSections [
	  0  ()
	  0  [/section ( Friday evening, Cantley House)]
	 10  ()
	 10  [/section ( Saturday afternoon, Walter Arms)]
	 20  ()
	 20  [/section ( Saturday evening, Cantley House)]
	200  ()
	200  [/section ( Multiple sessions)]
] def

 Page mirroring

◊ Generally one should print using toner not ink, as a single drop of wine or water causes ink to smudge. Alternatively, one could print the glasses mats onto acetate, and use the non-printed side. This requires mirroring the page, this being controlled by the eight arrays MirrorPagesGlasses, MirrorPagesTastingNotePages, MirrorPagesVoteRecorder, MirrorPagesDecantingNotes, MirrorPagesCorkDisplay, MirrorPagesPrePour, MirrorPagesPlaceNames, MirrorPagesDecanterLabels, and MirrorPagesStickyLabels. These are of the same length as the arrays PageOrdering…, though contain booleans. By default all values are false.

Use of page mirroring should be accompanied by use of PageOrdering…, to ensure that the acetates are consecutive.

 Numbers of copies

For most types of sheet, there is a parameter controlling how many copies appear. Already described are DecanterLabelsNumCopies, StickyLabelsNumCopies, PrePourNumCopies, DecantingNotesNumCopies. Analogously, there are parameters GlassesNumCopies and TastingNotePagesNumCopies, both defaulting to 1. For the vote-recorder sheets the parameter is a boolean, VoteRecorders.

GlassesNumCopies has a role that is not obvious. For both the pre-pour sheets and the sticky labels what appears there is a scaled version of that on the glasses sheets. So if a wine does not appear on the glasses sheets, it cannot appear on the pre-pours or sticky labels. But what if this is wanted? What if the pre-pour sheets should be known wines such as D63 F63 G63 T63, but the glasses sheets should be a blinded version of this such as α63 β63 γ63 δ63 (example of such a tasting)? Then construct additional glasses sheets to hold the material for the extra pre-pour or sticky-label sheets, but suppress their output with something like /GlassesNumCopies {SheetNum 4 ge {0} {1} ifelse} def. That done, the values of GlassesOnTastingNotePages and GlassesClusteredOnDecantingNotes might also need work.

 Suppressing pages

You have made the placemats for somebody else’s large tasting. But that somebody else wants to change a font; or doesn’t know what is a pre-pour sheet nor whether they are wanted. One could make several new versions, each of several megabytes and several hundred pages, and email those. But only a few pages are relevant. One could kill the other pages by specifying 0 copies or setting their presence to false, and by reducing the number of wines and people. What a faff, and because of the interactions between font sizes, doing so might change the shown pages. Instead suppress temporarily-unwanted page types with the array TestingSuppressPageTypes, which can contain any of /Glasses /TastingNotes /PlaceName /PrePour /StickyLabels /VoteRecorder /DecantingNotes /CorkDisplay /DistillerLog. Also set TestingMaxNumPagesToShow to a small integer, which will suppress all subsequent pages.

 Placemat ©

Who owns the © of the output, of the placemats? The parameter CopyrightStatementPlacemats holds this, defaulting to “Copyright 2015 Julian D. A. Wiseman of”. Obviously, adjust to your needs, copying the form. By default others may use the output, as given in the human-readable text LicensingAgreementTextPlacemats, defaulting to “This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International Licence.” There is the related parameter LicensingAgreementLinkPlacemats, defaulting to ( Obviously LicensingAgreementTextPlacemats and LicensingAgreementLinkPlacemats should be consistent. It is hoped to embed these permissions, and perhaps additional parameters, in a machine-readable manner. Please could those with expertise in the use of pdfmark read the request for help, and then help.

 Code within parameters

Another manual page explains how and why to vary the parameters by sheet or by glass, and how and why to add code inside compound strings.

Page typeTypeOfPagesBeingRenderedURL ending of first
page of this type
Tasting notes/TastingNotes…#TastingNotes_0
Vote recorders/VoteRecorder…#VoteRecorder_0
Decanting notes/DecantingNotes…#DecantingNotes_0
Cork display/CorkDisplay…#CorkDisplay_0
Pre-pour pages/PrePour…#PrePour_0
Place names/PlaceName…#PlaceName_0
Decanter labels/DecanterLabels…#DecanterLabels_0
Sticky labels/StickyLabels…#StickyLabels_0

 Linking to specific pages within the PDF

So that it is possible to link to specific pages within the PDF, the PDF includes some ‘nameddest’s. However, the use of these is imperfectly reliable (see help received). It seems to work when opening a PDF within the browser, but if the PDF is read by a separate application, it seems not to work.

To link to the first of the pages of glasses the URL should end …#Glasses_0. For second page, …#Glasses_1; etc. Links for other types of pages are shown in the table on the right. The log file also contains a list of the “URL # tags” added to the PDF.

 Errors: causation and avoidance

This is a PostScript program, and its various parameters are entered directly in PostScript. The program does little error checking. If parameters are malformed (e.g., non-matching parentheses), or if the parameters have nonsense values, then the output might be inelegant, incomplete, or non-existent.

If it just won’t work, then start again with the code as published at Does that distill correctly? Then change the Titles etc, and set the Circlearrays to be something simple of the same length. Does that distill correctly? Then add any required complexity to the Circlearrays, and re-test, before setting the other parameters one at a time. If you believe yourself to be coping competently, and it still won’t work, contact the author, enclosing in the email a link to the PostScript file and the log file produced by the distiller, and saying which program you use for the ps→pdf conversion.

The program outputs to a log file. This can contain various ‘Error’s, ‘Warning’s, and ‘Advice’s, as well as values of variables and other diagnostics. Perusal of this data might help. If OutputLogToPage is still at its default value of true, this log file also appears at the end of the output. There is the analogous parameter OutputLogToLog, and LogThisExtra, a user-chosen string which is output to the log.


The author welcomes comment on this program, which may be by email or in the appropriate thread on The Port Forum (there also being a thread showing the used parameters from actual tastings).

 Who to invite?

Permission is given to make non-commercial use of this program as you see fit, and to distribute its output. But not to distribute the code: refer interested parties to the latest version via this page (​placemat/​placemat.html). Those with improvements to the code are invited to send them to the author.

It hardly needs saying that the finest way to thank me for this excellent product would be an invitation to your tasting! I’m particularly fond of Port and Madeira, and to a lesser extent of whisky and beer, but am willing to have my horizons broadened. Let me check my diary… yes, that evening is good—thank you very much indeed.

— Julian D. A. Wiseman

 Recent changes

January 2015

October 2014

September 2014

August 2014

July 2014

June 2014

May 2014

Main index Top About author