Script Anatomy

A “script” is the short-cut name for a file containing a list of instructions that will be read and processed by Python. The script filename is usually given an extension of .py

Hint

This document assumes that protograf is working on your computer after successfully Setting Up, and that you have read and understood the Basic Concepts

Start, Middle and End

A script will normally start with a Create command, then contain a series of other commands with the instructions for your particular needs (each command can run over multiple lines).

Hint

If your needs are more complex, you have the options of embedding “pure” Python commands and/or using tools provided by other Python libraries.

If the design you are working on requires multiple pages, then a PageBreak command can be inserted, followed again by the specific commands you need. A PageBreak is not needed when working with Card Decks.

The final command in the script will be the Save command, which triggers the creation of the output; by default a PDF file — optional PNG, SVG or animated GIF output is available as well.

Key Commands

Create Command

^

The Create() command is the essential command that must appear first in every script (unless you choose the Load Command instead).

Create() sets up the document so that it can support, or use, all of the elements that will appear after it.

Hint

If you omit the Create() command, you should get a FEEDBACK message:

FEEDBACK:: Please ensure Create() command has been called first!

By default, this command will setup an A4 page — in portrait mode — with margins of one-quarter inch (0.625cm), and units of centimetres; the resulting output file will have the same name as the script, but with a .pdf extension.

To customise the command, set its properties as follows:

  • filename - name of the output PDF file; by default this is the prefix name of the script, with a .pdf extension

  • fill - set the color for the page; the default page color is white

  • color_model - sets the model used to create any default, or built-in colors; this can be "RGB" (the default) or "CMYK"

  • paper - use a paper size from either of the ISO series - A0 down to A8; or B6 down to B0 - or a USA type - letter, legal or elevenSeventeen; to change the page orientation to landscape simply append -l to the name — for example, "A3-l" is a landscape A3 paper size

  • paper_width - set a specific paper width using the defined units

  • paper_height - set a specific paper height using the defined units

  • margin - set the value for all margins using the defined units

  • margin_top - set the top margin

  • margin_bottom - set the bottom margin

  • margin_left - set the left margin

  • margin_right - set the the right margin

  • margin_debug - set to True to show the margin as a dotted blue line

  • page_grid - if set to a number, will display a squared grid of thin horizontal and vertical lines, set a distance “unit” apart — where the distance depends on the current units

  • units - these can be cm (centimetres), in (inches), mm (millimetres), or points; the default is cm

Example 1. Create Options

Here is an example of a customised Create command, for an A3-sized page in landscape mode, with units of inches (in) and top and left margins being set to 2 inches each:

Create(
    paper="A3-l",
    units="in",
    filename="testA3.pdf",
    margin_top=2,
    margin_left=2,
)

Example 2. Grid and Margin Display

cr1

Here is an example of a customised Create command, for an A8-sized page in portrait mode, with margins being 0.5 cm each. A grid of 0.5 cm is displayed and the margins are shown as dotted lines.

This type of setup is useful when working on a design but is typically not shown as part of a final product.

Create(
    filename="blank.pdf",
    paper='A8',
    margin=0.5,
    page_grid=0.5,
    margin_debug=True,
)

PageBreak Command

^

The PageBreak() command is only needed when you need to start a new page.

When generating a deck of cards the program will automatically insert PageBreak() commands as needed, if the cards occupy multiple pages.

Save Command

^

The Save() is usually the last to appear in a script.

The Save() command, by default, simply results in the outcome of all the commands used to that point being written out to a PDF file; either with a default filename, or with the one set in the Create Command .

To customise the command, set its properties as follows:

  • output - this can be set to:

    • png - to create one image file per page of the PDF; by default the names of the PNG files are derived using the PDF filename, with a - followed by the page number;

    • svg - to create one file per page of the PDF; by default the names of the SVG files are derived using the PDF filename, with a - followed by the page number;

    • gif - to create a GIF file composed of all the PNG pages (these will be removed after the file been created)

  • directory - sets the location where the output will be created; the default is the directory on which the script is being run

  • dpi - can be set to the dots-per-inch resolution required; by default this is 300

  • names - this can be used to provide a list of names — without an extension — for the output files that will be created from the PDF; the first name corresponds to the first page, the second name to the second and so on. Each will automatically get the correct extension added to it. If the term None is used in place of a name, then that page will not have an output file created for it.

  • cards - when set to True will cause all the card fronts to be exported as PNG files; the names of the files are based on the PDF filename, with a dash (-) followed by the page number, and .png file extension

  • framerate - the delay in seconds between each “page” of a GIF image; by default this is 1 second

  • stop - when set to True will cause the script to stop at that point, after saving the file — this can be useful when you have a long script and want to verify output with adding or displaying all the elements

Example 1. Save PNG

Here is an example of a customised Save command:

Save(
    output='png',
    dpi=600,
    names=['pageOne', None, 'pageThree']
)

In this example, assuming that three pages are created by the script, no PNG file will be created from the second page, while .png files named pageOne.png and pageThree.png will be created from the first and third pages of the PDF file.

Example 2. Save GIF

Here is another example of a customised Save command:

Save(
    output='gif',
    dpi=300,
    framerate=0.5
)

In this example, an animated GIF image will be created, assembled out of the PNG images; one per page of the PDF. There will be a delay of half-a-second between the showing of each image.

Example 3. Customise Outputs

Here are various examples of a customised Save command:

# 1.
Save()
# 2.
Save(directory="/tmp/test")
# 3.
Save(output="png", directory="/tmp/test")
# 4.
Save(cards=True, directory="/tmp/test")
# 5.
Save(cards=True, output="png", directory="/tmp/test")
# 6.
Save(cards=True, output="png")

The outcomes will be as follows:

  1. The PDF for the script will be created in the directory where its being run

  2. The PDF for the script will be created in the /tmp/test directory, which must already exist

  3. The PDF for the script will be created in the /tmp/test directory, which must already exist, as well as a PNG image for each page in the PDF

  4. The PDF for the script will be created in the /tmp/test directory, which must already exist, as well as a PNG image for each card in the PDF (this example assumes you are working with the Deck command)

  5. The PDF for the script will be created in the /tmp/test directory, which must already exist, as well as a PNG image for each page in the PDF, and also a PNG image for each card in the PDF (this example assumes you are working with the Deck command)

  6. The PDF for the script will be created in the directory where its being run as well as a PNG image for each page in the PDF, and also a PNG image for each card in the PDF (this example assumes you are working with the Deck command)

Other Commands

Load Command

The Load() command is an alternative to the Create() command, and should appear first in the script, instead of it.

Hint

If you omit the Create() command and the Load() command, you should get a FEEDBACK message:

FEEDBACK:: Please ensure Create() command has been called first!

To use this command, set its properties as follows:

  • filename - name of the input PDF file

Note that paper_width and paper_height will be calculated from the first page loaded.

The Load() command is useful in conjunction with the Extract command.

Shape, Grid, Deck & Card Commands

There are numerous other commands which are either used to draw shapes, or sets of shapes, or to control how and where sets of shapes appear on a page. See:

Comments

It can be useful to “annotate” a script with other details that can remind you, as a reader, about any of the “what” or “why” aspects of the script.

These comments are effectively ignored by Python and protograf and have no effect on the output.

Single Line Comments

Simply insert a #, followed by space, at the start of the comment line:

# this is the rim of the clock
Circle(stroke_width=5)

Multiple Line Comments

Use a pair of triple-quotes to surround all the lines of comments:

"""
This is a useful script.
It was created to remind me about Circles.
It should not be used for normal designs.
"""
Circle(stroke_width=5)

Make sure the triple quotes appear at the start of the lines in which they are used.

Drawing vs Assigning

All of the shape commands can either be called with a capital letter or a lowercase letter.

The use of a capital is the more common case, and it effectively tells protograf to “draw this shape now”:

Circle(stroke_width=5)

The use of a lowercase is normally when you assign a shape to a name, so that it can be used — or drawn — later on in the script:

# this circle is *not* drawn at this point of the script
clock = circle(stroke_width=5)

# the circle - aka "clock" - drawn when cards are drawn
Card("1-9", clock)

Basic Shapes

protograf allows for the creation of many shapes, with a command for each one.

These are described in the Core Shapes section, which also covers common customisation options.

More extensive customisation of some shapes is also possible; see the Customised Shapes section.

Card Decks

A common element in many games is a deck - or multiple decks - of cards. protograf also considers items such tiles or counters to be “cards”; they are really just “shapes containing other shapes”

There are two key commands for creating a deck of cards: the Card() and the Deck(). These are discussed in detail in the card decks section, while the options for customisation of the deck itself are discussed in the Deck command.

A useful “getting started” approach is to look through the section with worked examples which shows an increasingly complex set of examples for setting up and running scripts to generate a deck of cards.

Layouts, Sequences, Tracks and Grids

A basic layout is that of a simple sequence, with shapes placed at regular positions in a linear direction.

A track can be defined as the borders of a rectangle or polygon shape; or at specific angles along the circumference of a circle. Shapes can then be placed at these locations.

The other way that elements can be laid out on a page is through a grid layout which can be derived from a built-in shape such Hexagons or constructed using a defined set of properties.

These are all described in the Layouts section.

There is also a separate section on Hexagonal Grids which describes the variety of these types of grids, as well as some options for adding shapes to them.

The FEEDBACK Message

Normally, a script will run without you seeing anything. However, there are some occasions when you will see feedback or warning message of some kind.

  1. An error happens - this is described further in the section on making mistakes

  2. Generating Images from Save() - this will show a message like:

    FEEDBACK:: Saving page(s) from "/tmp/test.pdf" as PNG image file(s)...
    
  3. Accessing BGG - you can enable progress when using the BGG() command, to retrieve boardgame information, as follows:

    # progress is True - games retrieval is shown
    BGG(ids=[1,2,4], progress=True)
    

    In this case you will see messages like:

    FEEDBACK:: Retrieving game '1' from BoardGameGeek...
    
  4. An empty Layout - this is just a warning issued because the Layout() has no shapes allocated for it to draw:

    rect = RectangularLayout(cols=3, rows=4)
    Layout(rect)
    

    then you will see a message like:

    WARNING:: There is no list of shapes to draw!
    

    This is not an error, but does act as a reminder about what might still be needed.

Making Mistakes

It is, unfortunately, all too easy to make mistakes while writing scripts. Some common types of mistakes are listed below — these are in no way meant to be comprehensive!

Supplying the script an incorrect value, for example, giving the location a value of 3.0 when you meant to give it 0.3; this kind of mistake can usually be detected when you look at the PDF, although it may not be immediately obvious exactly what has happened.

Supplying the script an incorrect kind of value, for example, giving the y location a value of a instead of a number. The script will stop at this point and give you a feedback message:

FEEDBACK:: The "a" is not a valid float number!
FEEDBACK:: Could not continue with script.

Supplying the script a property that does not exist, for example, using u=2.0 when you meant to say y=2.0. This can happen because those two letters are located right next to each other on a keyboard and the letters are a little similar. In this case, the script will “fail silently” because properties that don’t exist are simply ignored. This kind of mistake is much harder to spot; often because the default value will then be used instead and it will seem as though the script is just drawing something incorrectly.

Supplying the script with a duplicate property, for example:

display = hexagon(stroke="black", fill="white", height=2, stroke=2)
                                                          ^^^^^^^^
SyntaxError: keyword argument repeated: stroke

This kind of mistake is usually easier to see as both keywords, in this case, are part of the same command and the error message that you see also highlights the repetition with the ^^^^^^^^ characters.

Hint

Errors are discussed further in the Script Errors section.