Generator of customizable SVG displays of the US flag
See the official math specifications in Executive Order 10834.
These are found in the py_spangled_banner
module.
write_svg(file: str|io.TextIOBase, /, nstars: int, *, canton_factor: Rational = Fraction(247, 175), kinds: Iterable[stars.LayoutKind|str]|None = None, nstripes: int = 13, proportional_star_size: bool = True, width: float|str|None = None, height: float|str|None = None, colors: svg.FlagColors = FlagPalette.DEFAULT)
This function writes an SVG file representing a stars-and-stripes flag. The parameters are as follows:
-
file: str|io.TextIOBase
: a file-like object open in text mode, or the path to the file to write on. If a path is provided, the file will be written ti in UTF-8 encoding, and it will be created if it doesn't exist or overwritten if it does. -
nstars: int
: the number of stars to display in the canton. -
The other keyword parameters are passed to functions from the submodules used by this function:
stars.find_best_star_layout
:canton_factor
andkinds
geometry.Measurements.generate
:nstripes
andproportional_star_size
svg.get_svg_from_layout
:width
,height
andcolors
get_svg(nstars: int, *, canton_factor: Rational = Fraction(247, 175), kinds: Iterable[stars.LayoutKind|str]|None = None, nstripes: int = 13, proportional_star_size: bool = True, width: float|str|None = None, height: float|str|None = None, colors: svg.FlagColors = FlagPalette.DEFAULT) -> str
Instead of writing it to a file, this function returns the SVG content as a string. The parameters are otherwise the same.
These are found in the py_spangled_banner.stars
module. This submodule generates layouts for the stars in the canton.
LayoutKind
This is an enumeration of the possible kinds of layouts for the stars in the canton.
GRID
The stars are arranged in a grid, like the 24-star "Old Glory" flag, or the 48-star flag.
SHORT_SANDWICH
Each shorter row of stars is between two longer rows, like the 50-star flag. It can be seen as two grids, one inside the other.
LONG_SANDWICH
Each longer row of stars is between two shorter rows. It looks like a rectangle with the corners cut off.
PAGODA
Each longer row of stars is followed by a shorter row, like the 45-star flag. It looks like a rectangle with two corners on the same long side cut off. (This module will always cut off the corners of the bottom side.)
SIDE_PAGODA
The rows are all of the same length and there is an odd number of them, like the short-lived 49-star flag. Each longer column of stars is followed by a shorter column, and it looks like a rectangle with two corners on the same short side cut off, making it similar to the pagoda layout but on the side. (This module will always cut off the corners of the right side.)
CUBE
The rows are all of the same length and there is an even number of them. It looks like a rectangle with two opposite corners cut off. (This module will always cut the top-right and bottom-left corners.)
from_layout(layout: tuple[int, int, int, int], /) -> LayoutKind
This static method computes the layout kind from a given 4-tuple layout. More about what those tuple layouts mean in the following function.
generate_star_layouts(nstars: int, *, kinds: Iterable[LayoutKind|str]|None = None) -> Iterable[tuple[int, int, int, int]]
This is a generator for all the possible layouts, in arbitrary order, for the given number of stars, optionally filtered by a set of layout kinds.
The (a, b, c, d)
layouts represent that a
rows of b
stars are interspersed with c
rows of d
stars.
find_best_star_layout(nstars: int, *, canton_factor: Rational = Fraction(247, 175), kinds: Iterable[LayoutKind|str]|None = None) -> tuple[int, int, int, int]
This returns the best possible layout for the given number of stars and canton size ratio (width over height) defaulting to the official US canton ratio.
find_best_star_layouts(nstars: int, *, canton_factor: Rational = Fraction(247, 175), kinds: Iterable[LayoutKind|str]|None = None) -> dict[tuple[int, int, int, int], Comparable]
The keys of the dict are the same layouts generated by generate_star_layouts
, but sorted by how well it fits the given canton size ratio, the first the better. The values are arbitrary comparable values : the lower, the better it fits.
These are found in the py_spangled_banner.geometry
module. This submodule generates measurements and coordinates for elements of the flag.
Measurements
This is a class that holds the measurements defining the geometry of the flag, similar to the government specifications described in Executive Order 10834.
The constructor takes 10 parameters, all floats in the same unit : height
, width
, canton_height
, canton_width
, vertical_stars_margin
, vertical_star_spacing
, horizontal_stars_margin
, horizontal_star_spacing
, star_diameter
and stripe_height
. They are available as attributes. Measurements
instances are read-only and immutable.
generate(*, stars_layout: tuple[int, int, int, int] = (5, 6, 4, 5), nstripes: int = 13, proportional_star_size: bool = True) -> Measurements
This static method generates the specifications for a flag with the given layout (which includes the number of stars) and number of stripes. The `proportional_star_size` parameter enables the star size to be scaled to fit best, in a way which makes the 50-star flag same as the official specifications.
coordinates_from_layout(layout: tuple[int, int, int, int], /, *, nstripes: int = 13, proportional_star_size: bool = True) -> Iterable[tuple[float, float]]
This generates, in arbitrary order, the coordinates of the stars inside the canton, relative to the canton size.
These are found in the py_spangled_banner.svg
module. This submodule generates SVG content from the measurements and coordinates.
FlagColors
This is a dataclass that holds the colors of a flag, stored as strings and supported by the SVG standard.
outer_stripes
The color of the outer stripes, which are red in the official flag.
inner_stripes
The color of the inner stripes, which are white in the official flag.
canton
The color of the canton, which is blue in the official flag.
stars
The color of the stars, which are white in the official flag.
FlagPalette
This is an enumeration of built-in FlagColors presets.
DEFAULT
: the official colors
SATURATED
: the most saturated red, white and blue colors
write_svg_from_layout(file: str|io.TextIOBase, /, measurements: Measurements, layout: tuple[int, int, int, int], *, width: float|str|None = None, height: float|str|None = None, colors: FlagColors = FlagPalette.DEFAULT)
This function writes an SVG file representing a flag from the given measurements and star layout. The parameters are self-explanatory.
write_svg_from_star_coordinates(file: str|io.TextIOBase, /, measurements: Measurements, star_coordinates: Collection[tuple[float, float]], *, width: float|str|None = None, height: float|str|None = None, colors: FlagColors = FlagPalette.DEFAULT)
This function instead takes arbitrary star coordinates. They can be passed as several kinds of Collections (a tuple, list, set of pairs of floats), but if given as a dict, the values of the dict are taken as being float multipliers of the star size given in the measurements
parameter.
The get_svg_from_layout
and get_svg_from_star_coordinates
functions are similar, but return the SVG content as a string instead of writing it to a file (and they do not take a file parameter).
- Consider using etree in the SVG submodule, especially as part of handling the layouts
- Add other builtin palettes
- Enable the layout generators to take a layout kind constraint, and only
return layouts of that kind
- Enable that constraint to be passed through from the main function in init
- Make the SVG builder take a sequence of relative coordinates inside the
canton, or a dict whose values are the diameter of the stars
- Add, somewhere, a function generating the coordinates of the stars
relative to the canton based on the layout
- Add optional margin parameters ?
- Put the builder taking a layout elsewhere ?
- Or in the main module, have a builder that takes just a number of stars (as well as other measurements data) ?
- Add, somewhere, a function generating the coordinates of the stars
relative to the canton based on the layout
- In Measurements.generate:
- Add xmargin and ymargin parameters, floats relative to the canton size which make up (or add to ?) the respective margins, and compute the stars spacing accordingly
- Make the star size proportional to the canton size and the layout
- Add either a threshold system or a boolean parameter so that the 50 flag remains the same
- May cause issues with the no-layout builder version - but generate requires a layout anyway so it's a bigger issue
- In the SVG writer, fix:
- Sizing the stars arbitrarily using a dict
- The layout method for all layout kinds
- Add a CLI
- Make the normalize function reduce the denominator of the star size when the lcm is too high, rather than doing that preventively