Making Art
ElkPlot assumes that you are creating your plotter art using the Shapely Python library. This documentation assumes that you are already comfortable/familiar with Shapely. ElkPlot primarily deals with LineString
, MultiLineString
, and GeometryCollection
, so you should try to compose your art in terms of these types.
- A
LineString
will be plotted as a single stroke of the pen - the plotter will go to the first coordinate in theLineString
, put the pen down, and then travel to each subsequent coordinate until it reaches the end of theLineString
at which point the pen will be lifted again. (ALinearRing
will be plotted as though it were a LineString with the first coordinate duplicated at the end.) - A
MultiLineString
will be plotted as multiple discrete strokes. The plotter draws eachLineString
contained within in the order that they are given, lifting the pen between eachLineString
in order to travel to the next. - A
GeometryCollection
will be treated as multiple passes with multiple pens. If you have a drawing that uses two colors, you should compose aMultiLineString
containing all the lines to be drawn in the first color, and a secondMultiLineString
containing all the lines to be drawn in the second color. Then create aGeometryCollection
containing both.
import shapely
first_color = shapely.MultiLineString([...])
second_color = shapely.MultiLineString([...])
drawing = shapely.GeometryCollection([first_color, second_color])
Helpful Functions for Creating Plottable Shapely Geometry
The following functions can be imported directly from elkplot and help manipulate Shapely geometry in specific ways that are useful for plotting.
center(drawing, width, height, x=0, y=0)
Return a copy of a drawing that has been translated (but not scaled) to the center point of a given rectangle
Args:
drawing: The drawing to translate
width: The width of the rectangle in inches (or any other unit if you pass in a pint.Quantity
.)
height: The height of the rectangle in inches (or any other unit if you pass in a pint.Quantity
.)
x: x-coordinate of the upper-left corner of the rectangle in inches (or any other unit if you pass in a pint.Quantity
.)
y: y-coordinate of the upper-left corner of the rectangle in inches (or any other unit if you pass in a pint.Quantity
.)
Returns:
Type | Description |
---|---|
Geometry
|
A copy of the drawing having been translated to the center of the rectangle |
Source code in elkplot/shape_utils.py
flatten_geometry(geom)
Given any arbitrary shapely Geometry, flattens it down to a single MultiLineString that will be rendered as a
single color-pass if sent to the plotter. Also converts Polygons to their outlines - if you want to render a filled
in Polygon, use the shade
function.
Args:
geom: The geometry to be flattened down. Most often this will be a GeometryCollection or a MultiPolygon.
Returns:
Type | Description |
---|---|
MultiLineString
|
The flattened geometry |
Source code in elkplot/shape_utils.py
layer_wise_merge(*drawings)
Combines two or more multi-layer drawings while keeping the layers separate. That is, creates a new drawing where the first layer is the union of all the input drawings' first layers, and the second layer is the union of all the input drawings' second layers, and so on. Args: *drawings: All the drawings to be merged
Returns:
Type | Description |
---|---|
GeometryCollection
|
The merged drawing |
Source code in elkplot/shape_utils.py
metrics(drawing)
Calculate the pen down distance, pen up distance, and number of discrete paths (requiring penlifts between) in a given drawing. Args: drawing:
Returns:
Type | Description |
---|---|
DrawingMetrics
|
A |
Source code in elkplot/shape_utils.py
optimize(geometry, tolerance=0, sort=True, reloop=True, delete_small=True, pbar=True)
Optimize a shapely geometry for plotting by combining paths, re-ordering paths, and/or deleting short paths.
Always merges paths whose ends are closer together than a given tolerance.
Can also randomize the starting point for closed loops to help hide the dots that appear at the moment the pen hits
the page.
Args:
geometry: The shapely geometry to be optimized. Usually this is either a MultiLineString
or a
GeometryCollection
depending on if you are optimizing a single layer or a multi-layer plot.
tolerance: The largest gap that should be merged/the longest line that should be deleted in inches (or any other unit if you pass in a pint.Quantity
.)
sort: Should the paths be re-ordered to minimize pen-up travel distance?
reloop: Should closed loop paths have their starting point randomized?
delete_small: Should paths shorter than tolerance
be deleted?
pbar: Should progress bars be displayed to keep the user updated on the progress of the process?
Returns:
Type | Description |
---|---|
Geometry
|
The optimized geometry |
Source code in elkplot/shape_utils.py
rotate_and_scale_to_fit(drawing, width, height, padding=0, increment=0.02)
Fits a drawing into a bounding box of a given width and height, but unlike scale_to_fit
also rotates the shape to
make it take up as much of that area as possible. Also centers the object in that bounding box
with the bounding box's upper-left corner at the origin.
Args:
drawing: The shapely geometry to rescale
width: The width of the bounding box in inches (or any other unit if you pass in a pint.Quantity
.)
height: The height of the bounding box in inches (or any other unit if you pass in a pint.Quantity
.)
padding: How much space to leave empty on all sides in inches (or any other unit if you pass in a pint.Quantity
.)
increment: The gap between different rotation angles attempted in radians. (smaller value gives better results,
but larger values run faster.)
Returns:
Type | Description |
---|---|
Geometry
|
A copy of the drawing having been rotated, rescaled, and moved such that the new upper-left corner of the bounding box (including the padding) is at the origin |
Source code in elkplot/shape_utils.py
scale_to_fit(drawing, width=0, height=0, padding=0)
Scales a drawing up or down to perfectly fit into a given bounding box. Also centers the object in that bounding box
with the bounding box's upper-left corner at the origin.
Args:
drawing: The shapely geometry to rescale
width: The width of the bounding box in inches (or any other unit if you pass in a pint.Quantity
.)
If this is 0, the drawing will be scaled to fit into the given height with arbitrary width.
height: The height of the bounding box in inches (or any other unit if you pass in a pint.Quantity
.)
If this is 0, the drawing will be scaled to fit into the given width with arbitrary height.
padding: How much space to leave empty on all sides in inches (or any other unit if you pass in a
pint.Quantity
.)
Returns:
Type | Description |
---|---|
Geometry
|
A copy of the drawing having been rescaled and moved such that the new upper-left corner of the bounding |
Geometry
|
box (including the padding) is at the origin |
Source code in elkplot/shape_utils.py
shade(polygon, angle, spacing, offset=0.5)
Fill in a shapely Polygon or MultiPolygon with parallel lines so that the plotter will fill in the shape with lines.
Args:
polygon: The shape to be filled in
angle: The angle at which the parallel lines should travel in radians (or any other unit if you pass in a pint.Quantity
.)
spacing: The gap between parallel lines in inches (or any other unit if you pass in a pint.Quantity
.)
offset: How much should the parallel lines be shifted up or down as a percentage of the spacing?
Returns:
Type | Description |
---|---|
MultiLineString
|
The MultiLineString of the shaded lines. (NOTE: Does not include the outline.) |
Source code in elkplot/shape_utils.py
size(geom)
Calculate the width and height of the bounding box of a shapely geometry. Args: geom: The shapely Geometry object to be measured
Returns:
Type | Description |
---|---|
Quantity
|
width in inches |
Quantity
|
height in inches |
Source code in elkplot/shape_utils.py
up_length(drawing)
Calculate the total distance travelled by the pen while not in contact with the page.
This can be improved by merging and/or reordering the paths using the optimize
function.
Args:
drawing: A single layer of plotter art
Returns:
Type | Description |
---|---|
Quantity
|
The total pen-up distance in inches |