Main index Other Papers index About author

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?; Version history.

Publication history: only here. Usual disclaimer and copyright terms apply. Also see the PostScript program itself, and the example PDF output.


This is the ‘documentation’ for the April 2008 version, which is not necessarily the final version. The code is mostly debugged, but errors surely remain. It is provided as-is, without liability—it is free.

There is a separate page documenting how to use code in parameters, something not recommended to new users of this software. Further, PostScript programmers are invited to peruse the 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 matching decanter labels, and pages for tasting notes. Pages are set as in the PDF example, the first page of which is also rendered below.


Example of an 10-glass port tasting placemat

Pre-canned pages have been made for those who host blind tastings, in pages sizes A4 = 11.70″×8.28″, A3 = 16.55″×11.70″, US Letter = 11″×8½″, US Legal = 14″×8½″, and US Ledger = 17″×11″. Each of these (large) files contains pages for numbers of glasses from 2 upwards, with pages unnamed and with names from “First Flight” to “Sixth Flight”.

So, if arranging a blind tasting for fifteen people, the first flight of 10 glasses and the second of 11, one would print, from the file of appropriate paper size:

  • fifteen copies of the 10-glass placemat entitled “First Flight”;
  • fifteen copies of the 10-glass tasting-note page entitled “First Flight”;
  • one copy of the 10-glass page of decanter labels;
  • fifteen copies of the 11-glass placemat entitled “Second Flight”;
  • fifteen copies of the 11-glass tasting-note page entitled “Second Flight”;
  • one copy of the 11-glass page of decanter labels.

(Even if using a large paper size for the placemat, it might be more convenient to use tasting notes on A4 or USL.)

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; the author has successfully used PS2PDF.com. The text file can be edited in any text editor, including Notepad and SimpleText; the author used Alpha X on the Mac. It is easier to use a text editor that has been configured to edit PostScript files, as such an editor will colour code helpfully.

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

In the example provided, Titles is defined thus:

/Titles [
	(C63)
	(C70)
	(C85)
	(C5?)
	(T55)
	(T77)
	(T85)
	(T63)
	(T70)
	(T85)
] def

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


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

/Subtitles [
	()
	()
	()
	[/quotedblleft (Believed 1950) /quoteright (s) /quotedblright]
	()
	()
	(Magnum)
	()
	()
	(Single)
] def

Observe that, in place of one of the strings, is an array of strings and other characters called glyphs, each beginning with a forward slash (“/”). Examples of glyphs include accented characters such as /atilde, and the likes of /lozenge, /bullet, /periodcentered or /daggerdbl, as well as ligatures such as that in [(Quinta do Bom) /fi (m)]. Some other glyphs are listed in appendix E.5 of the PostScript Language Reference Manual, third edition; a fuller list is at www.jdawiseman.com/​papers/​trivia/​character-entities.html, though most fonts do not contain all the glyphs in either list. Any string parameter may be replaced with an array of glyphs, strings, and indeed other like arrays.

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


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

/Circlearrays [
	[ (Cockburn) (1963) ]
	[ (Cockburn) (1970) ]
	[ (Cockburn) (1985) ]
	[ (Cockburn) [/quotedblleft (Believed 1950) /quoteright (s) /quotedblright] ]
	[ (Taylor) (1955) ]
	[ (Taylor) (1977) ]
	[ (Taylor) (1985) (magnum) ]
	[ (Taylor) (1963) ]
	[ (Taylor) (1970) ]
	[ (Taylor) (1985) (single) ]
] def

Each of the sub-arrays of Circlearrays contains strings; glyphs; or sub-sub-arrays arrays of these. The program calculates how many copies of the 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 at the top of the first page shown above), and these names are listed in yet another array, not necessarily of the same length as the previous three:

/Names [ (JDAW)
	[/Gbreve /uacute /ecircumflex /scedilla /tcommaaccent ( ) /Odieresis /ntilde /egrave]
	(Guest Two)
	() 
] def

As with the other parameters, strings may be replaced with arrays of glyphs and strings, in this case to make the silly but didactic “Ğúêşţ Öñè”. Including a blank name is very strongly recommended: last-minute changes to the guest list do happen.

Other parameters

Black “Fonseca” overlapping grey “F”

The parameter OverlapSubtitlesOnTitles may be deffed to false, as in the PDF example rendered above; alternatively /OverlapSubtitlesOnTitles true def, which overlaps the sub-titles on the titles, as in the diagram on the right. This can work well for a horizontal tasting (comprising many houses from the same year).

The fonts in which the various text pieces are rendered are contained in the parameters TitlesFont, SubtitlesFont, FillTextFont, CircletextFont, and NamesFont. The program was designed for left-to-right alphabets, and only Roman fonts have been tested. (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 in rendering “泉十段”.)

Two parameters control the page size and the page orientation:

	/PaperType /A4 def
	/Orientation /Landscape def

In the first line allowed values are /A4 (11.70″×8.28″), /USL (11″×8½″), /A3 (16.55″×11.70″), /USLegal (14″×8½″), and /USL2 (17&Prime×11&Prime). (For convenience of copy-pasting, these allowed values appear in the comment at the end of the line—after the “%”.) In the second line allowed values are /Landscape and /Portrait.

Example of titles filled with text

If FillTitles or FillSubtitles is true, then the program accesses another array called FillTexts, which is of the same length as Titles. This is used to ‘fill’ the Titles (or Subtitles) with repeated small copies of the FillTexts, outlined FillTextNumOutlines times. If OverlapSubtitlesOnTitles is false, then the filling text is black, with FillTextNumOutlines in alternate white and black. If OverlapSubtitlesOnTitles is true, the Titles are filled in the same pattern with 60% black and 0% = white; and the Subtitles are filled with 100% and 20% black (as in the 2× diagram on the right). The additional parameter FillTextAngle may be deffed to a number (30 being a good choice), this being the angle 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. Each rendering of an item of FillTexts is suffixed with FillTextNumSpaces spaces. In the example on the right the relevant item of Titles is (S); of Subtitles is (Sandeman); of Circlearrays is [(Sandeman) (1985)]; of FillTexts is (1985), with FillTextNumSpaces being 1.75 and FillTextAngle being 30, and all the typefaces being /HelveticaNeue-CondensedBold. Use of FillTexts greatly slows distillation time, and can also make the PDF files very large and complicated. Such files can be too complicated for some printers. Test your printer; do not assume that anything will work first time—and it is not always true that 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). If GlassesOnSheets specifes a two-page layout, then CodeForGlassSheets defaults to setting FillTextAngle to be /LowerRight on the first sheet, and /LowerLeft on the second.

Second example of CrossHatchingTitles and CrossHatchingSubtitles The example on the left, and the CirclifyTitles example below right, are both filled with a check pattern. This check is activated by booleans CrossHatchingTitles and CrossHatchingSubtitles. The polar gridlines originate from a point with x coordinate CrossHatchingCentreX which can take values of /Name, /Left, /Center, or /Right; and y coordinate CrossHatchingCentreY with possible values /Name, /Bottom, /Middle, or /Top. Lines are formatted and stroked by the code in /CrossHatchingTitlesFormatStroke and /CrossHatchingSubtitlesFormatStroke (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 OverlapSubtitlesOnTitles is false and hence the text in black and the lines defaulting to white.

Example of titles circlified

Another flamboyant option that can be set is controlled by the booleans CirclifyTitles and CirclifySubtitles, which apply a transformation to either or both pieces of text, such that what would otherwise have been their joint bounding box vertically fills the circle. In the example on the right CirclifyTitles and OverlapSubtitlesOnTitles are both true. Using CirclifyTitles or CirclifySubtitles with FillTitles or FillSubtitles is even harder on many printers. Also, CirclifyTitles looks far better if the characters have exactly the same height above the baseline, and do not have descenders. If using a “J” good typefaces include /ArialRoundedMTBold (used in the example on the right), /AmericanTypewriter-CondensedLight and /Braggadocio. If not using a “J” other candidates include /GillSans, /GillSans-Light, /GillSans-Bold, /EurostileRegular, /EurostileBold, /Modern-Regular, /Onyx, /Stencil, and, though lacking a glyph for the “fi” ligature, /AmosExtendedNormal and /AmosThinNormal.

When there are few glasses on a page, the radius of the circles and the size of the text of the Titles could become very large. Hence the radius of the circles is bounded above by MaxRadius; the font size of the Titles by both MaxTitleFontSizeAbsolute and by MaxTitleFontSizeProportionRadius×the radius of the circles, and the font size of the Subtitles likewise by MaxSubtitleFontSizeAbsolute and MaxSubtitleFontSizeProportionRadius×radius. In the code MaxTitleFontSizeAbsolute is set to 160 or 130 dependent on the value of OverlapSubtitlesOnTitles, and MaxSubtitleFontSizeAbsolute to one third of MaxTitleFontSizeAbsolute. Also, the minimum separation (measured in space-widths) between the items of the sub-arrays of Circlearrays is defined by MinNumSpacesBetweenCircletexts.

The layout of the glasses can be rectangular, or pseudo-hexagonal. Sometimes the former is ugly. If /LayoutMayBeRectangular false def, the rectangular layout is not used.

If FixNumRows is deffed to be an integer, the number of rows is forced to be that integer. If not, the number of rows is chosen to maximise the radius.

The names appear at the top if NamesAtTop is true, and at the bottom if it is false. The names are rendered in the font NamesFont, at a size equal to the size of the Circlearrays (or rather, at the size at which the the Circlearrays would appear if MinCopiesCircletexts were ignored), subject to a minimum of NamesFontSizeMin and a maximum of NamesFontSizeMax.

Example of outlined titles

The Titles can be outlined by setting /OutlineTitles true def, as in the 2× diagram on the right. 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)/2 = the golden ratio) and OutlineTitlesMultiplierBlack (defaulting to unity). If OutlineTitlesAlsoSubtitles is true then Subtitles are also outlined; if false then Subtitles sit plainly atop the lines. This feature does not impose as high a burden on a printer as does FillTexts, but can still be difficult for some. Again, test your printer.

How big is the circle text? In points, not bigger than MaxCircletextFontSizeAbsolute; and as a proportion of the circles’ radius not bigger than MaxCircletextFontSizeProportionRadius. If, in a font size equal to the lesser of these two, a particular item in Circlearrays is too long to fit at least MinCopiesCircletexts times, then the font size is reduced for that circle such that it does.

Following a suggestion of the author’s father, /CirclesReplaceCircletext true def causes Circlearrays to be ignored, the glass places instead being bounded by a circle of width CirclesLineWidth, and filled according to the PostScript code in CirclesFillColour. But, in the author’s judgement, use of Circlearrays is generally more pleasing to the eye.

Whether or not to make decanter labels is controlled by the boolean flag ShowDecanterLabels.

By default there are also tasting-note pages (controlled by GlassesOnTastingNotePages, more details below), these pages being of size TastingNotesPaperType (defaulting to /A4 or /USL, depending on whether PaperType is an American size) and orientation TastingNotesOrientation (defaulting to /Portrait). The tasting-note pages are divided lightly 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 a size not exceeding TastingNotesColumnHeadingsMaxFontSize. The columns have widths proportionate to TastingNotesColumnRelativeWidths, an array of the same length as TastingNotesColumnHeadings. Technical aside: whilst these tasting-note pages are being rendered the program sets RenderingTastingNotesPages to true. Variables may be set to code that checks this flag.

Wine merchants and auction houses arranging commerical tastings may well want to label sheets with a brand. It is possible to define a header, with text HeaderLeftText, HeaderCenterText, and HeaderRightText, which are rendered left-aligned to the page, centered and right-aligned. These are shown in font HeaderFont, at size HeaderFontSize, with the baseline of the characters a distance HeaderBaselineFromPageTop from the top of the page (which should be inside the top margin). Likewise FooterLeftText, FooterCenterText, and FooterRightText are shown in FooterFont at size FooterFontSize, with the top of the footer a distance FooterTopFromPageBottom from page bottom (which should be inside the bottom margin). Using all of six of these text positions would be very cluttered. Also, to have different headers on glass sheets and tasting-note sheets set the text parameters to suitable code: {RenderingTastingNotesPages {(Tasting-note header)} {(Glass-sheet header)} ifelse}.

Example of watercounts

Particularly at a tasting of a sweet fortified wine, drinking water is important. If WaterCounts is true, then there are a set of little glass icons (example on right) with which to record water consumption: check one for each glass of water downed. The number of these is usually at least WaterCountTarget, each of size WaterCountSize and separated by gaps of width WaterCountGap. These should appear on the lower-right of the page for right-handed drinkers, and lower-left for left-handers, this being controlled by WaterCountPositions, an array of the same length as Names, each item of the array being one of /LowerLeft or /LowerRight. If there are multiple pages of glasses (see below), then on which of these pages should they appear? For the right handers this is controlled by the array of booleans WaterCountShowRight (defaulting to only the last page); and for the lefties WaterCountShowLeft (defaulting to only the first page). Nota Bene: WaterCountShowRight and WaterCountShowLeft must be the same length as GlassesOnSheets; whereas WaterCountPositions must be the same length as Names. This WaterCounts feature is experimental: the author welcomes comment.

Non-easy parameters

Imagine that sixteen wines are to be tasted—too many for one sheet of paper. What might be wanted is something like the diagram below: two sheets to hold the glasses, but one combined tasting-note page.

Stylised glasses sheet, 1 of 2 Stylised glasses sheet, 2 of 2 Stylised tasting-note sheet

This may be done using the complicated parameter GlassesOnSheets, which is an array of arrays, each of the inner arrays describing one page. Choose the wines that will or might be in the tasting, creating appropriate members of Titles, Subitles, Circlearrays, and FillTexts. Imagine that there are twenty-six such candidate wines, which are deemed to be numbered from 0 to 25 (emphasis: numbering always starts at zero). Then

/GlassesOnSheets [
	[ 0 1 2 3 4 5 6 7 ]
	[ 11 12 17 16 15 14 13 25 ]
] def

would specify two sheets: the first containing the first eight glass settings (from the arrays Titles etc); the second sheet containing the 12th, the 13th, the 18th, the 17th, the 16th, the 15th, the 14th, and the last, in that order. Thus GlassesOnSheets can be used to select glass settings from a too-large set, to control the order in which they appear on a page, and which appear on which page.

When the pages are generated, should pages belonging to the same person be consecutive, or those with the same content (apart from the name)? This is controlled by NamesInOuterLoop, which defaults to same-person (true) if all the pages are on the same size paper, otherwise to same-content (false).

In general, it looks nicer if most of the Titles (and likewise Subtitles) have matching type sizes. Which of Titles (Subtitles) are the same size is controlled by SameSizeTitlesIfAllOf (SameSizeSubtitlesIfAllOf), being an array of ‘condition flags’, the items of Titles (Subtitles) being the same size if all the conditions are met. So an empty set of conditions is always true: all the Titles (Subtitles) would then be the same size. Permitted conditions are as follows.

Code within parameters

It is possible to vary the parameters by sheet, as described at www.jdawiseman.com/papers/placemat/placemat-code.html.

It is possible to add code inside compound strings, as described at www.jdawiseman.com/papers/placemat/placemat-code.html

Errors: causation and avoidance

This is a PostScript program, and its various parameters are entered directly in PostScript. The program does very 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 or non-existent.

If it just won’t work, then start again with the code as published at www.jdawiseman.com. Does that distill correctly? Then change the Titles and Subtitles, 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 copy of the PostScript file, 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 various numbers and diagnostics. But some ps→pdf converters don’t produce a log file. If these diagnostics are wanted (for example, the author refers to the line beginning “SubtitleFontSizes/Radii =” when setting SameSizeSubtitlesIfAllOf to contain an array of constants), then set OutputLogToPage to true which will cause them to appear on an extra page at the end of the PDF file.

Comment

The author welcomes comment on this program, which may be by email or in the appropriate threads on For The Love Of Port, The Port Forum, or CellarTracker.

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 (www.jdawiseman.com/papers/​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 indeed whisky, beer and other wines), but am willing to have my horizons broadened: let me check my diary… yes, that evening is good. Thank you very much indeed—what should I wear, and should I bring cheese?

Julian D. A. Wiseman


Version history: last ½ year

April 2008

• Implemented CirclifyTitles and CirclifySubtitles.

February 2008

• Renamed TastingNotesColumnTitles to TastingNotesColumnHeadings, and added parameter TastingNotesColumnHeadingsMaxFontSize.

• Implemented /GuessArraySizeBoundaries.

January 2008

• Parameters related to filling extensively renamed, to allow separation of the boolean controls FillTitles and FillSubtitles which were previous the same.

• Added /SameSubtitleLength and array condition flags to SameSizeTitlesIfAllOf and SameSizeSubtitlesIfAllOf.

• Added OutputLogToPage and other improvements to error handling for those without access to a log file.

December 2007

• Implemented UserScratchDict, to allow robust holding of variables between calls of user code.

• Split MaxTitleFontSize into MaxTitleFontSizeAbsolute and MaxTitleFontSizeProportionRadius, and likewise split MaxSubtitleFontSize into MaxSubtitleFontSizeAbsolute and MaxSubtitleFontSizeProportionRadius.

• Implemented TastingNotesColumnTitles.

/Name added as possible value of FillTextAngle.

November 2007

• That black outline changed from 1.20pt to 0.96pt.

October 2007

• Implemented headers and footers.

• Improved vertical positioning of Subtitles when OverlapSubtitlesOnTitles is true.

• Implemented NamesAtTop.

• Fixed bug in FillTextNumSpaces.

• When OverlapSubtitlesOnTitles and UseFilltitles were both true, the Titles and Subtitles were insufficiently distinct. Black outline of both thickened from 0.48pt to 1.20pt.

• Implemented experimental new feaure WaterCounts.



Main index Top About author