Creating Shapes#

The Polygon Object#

GraphingLib allows you to create polygons by specifying their vertices. Here is an example with a random shape:

polygon1 = gl.Polygon(
    vertices=[(0, 0), (1, 1), (2, 0), (1, -1)],
    edge_color="C0",
    line_width=2,
    line_style="solid",
    fill=True,
    fill_color="C0",
    fill_alpha=0.5,
)

polygon2 = gl.Polygon(
    vertices=[(0.5, 1), (2, 1.2), (1.5, -0.3), (0.5, 0)],
    edge_color="C1",
    line_width=2,
    line_style="dashed",
    fill=False,
)

fig = gl.Figure(x_lim=(-0.5, 2.5), y_lim=(-1.5, 1.5))
fig.add_elements(polygon1, polygon2)
fig.show()

(png, hires.png, pdf)

../_images/shapes-1.png

The only required parameter is vertices, but you can customize the appearance of the polygon by specifying the other parameters above. The real power of the Polygon object comes from its methods. Here are some methods used to get information about a polygon:

print(polygon1.area) # 2.0
print(polygon1.perimeter) # about 5.66
print(polygon1.get_centroid_coordinates()) # (1.0, 0.0)

# Check if a point is inside the polygon
print(gl.Point(1, 0) in polygon1) # True

# Get the intersection points of the polygon with a curve, or the intersection points of the edges of two polygons
curve = gl.Curve.from_function(lambda x: 0.7 * x**3 - 1, x_min=-1, x_max=3, color="C1")
points = polygon1.create_intersection_points(curve)

fig = gl.Figure(x_lim=(-0.5, 2.5), y_lim=(-1.5, 1.5))
fig.add_elements(polygon1, curve, *points)
fig.show()

(png, hires.png, pdf)

../_images/shapes-2.png

With GraphingLib, whenever you see a get_..._coordinates method, you can safely assume there also exists a create_..._point or create_..._points method in order to get Point objects instead of coordinates (and vice versa).

There are also many methods which manipulate and transform polygons. Here are some examples of splitting, translating, and rotating polygons:

# Split a polygon into two using a Curve
split_left, split_right = polygon1.split(curve)
split_left.fill_color = "C2"
split_left.edge_color = "C2"
split_right.fill_color = "C3"
split_right.edge_color = "C3"

# Translate and rotate the split polygons
split_left.translate(-0.2, 0.5)
split_left.rotate(15)
split_right.translate(0.2, -0.5)
split_right.rotate(-15)

fig = gl.Figure(x_lim=(-0.5, 2.5), y_lim=(-1.6, 1.6))
fig.add_elements(polygon1, curve, split_left, split_right)
fig.show()

(png, hires.png, pdf)

../_images/shapes-3.png

And here are some examples of unions, scaling and skewing:

polygon2.fill = True
polygon2.fill_color = "C1"
polygon2.line_style = "solid"

# Create the union of two polygons
union = polygon1.create_union(polygon2)
union.fill_color = "C2"
union.edge_color = "C2"

# Scale, skew, and apply arbitrary linear transformation to the union
union.scale(x_scale=1.2, y_scale=1.4)
union.skew(0, -10)
union.translate(2.5, 0)

fig = gl.Figure(x_lim=(-0.2, 5), y_lim=(-2, 2))
fig.add_elements(polygon1, polygon2, union)
fig.show()

(png, hires.png, pdf)

../_images/shapes-4.png

Some of the most common shapes, such as rectangles and circles, have their dedicated classes to simplify their creation. These classes are detailed below.

The Rectangle Object#

Rectangles can be created easily by creating an instance of the Rectangle class as shown below:

# Create a Rectangle from the bottom left corner
rect = gl.Rectangle(x_bottom_left=0, y_bottom_left=0, width=10, height=10)

# Create a Rectangle from its center
rect2 = gl.Rectangle.from_center(x=0, y=0, width=10, height=10)

You can customize the appearance of Rectangles by specifying the following optional parameters: edge_color, line_width, line_style, fill (True or False), fill_color, and fill_alpha. Here is an example with different styles of Rectangles:

rect1 = gl.Rectangle(
    x_bottom_left=2,
    y_bottom_left=2,
    width=10,
    height=10,
    fill_color="C1",
    edge_color="C1",
    line_width=1,
    line_style="solid",
    fill=True,
    fill_alpha=1,
)

rect2 = gl.Rectangle(
    x_bottom_left=5,
    y_bottom_left=5,
    width=5,
    height=12,
    fill_color="C0",
    edge_color="C0",
    line_width=2,
    line_style="dashed",
    fill=True,
    fill_alpha=0.5,
)

rect3 = gl.Rectangle(
    x_bottom_left=0,
    y_bottom_left=0,
    width=14,
    height=19,
    edge_color="C2",
    line_width=5,
    line_style="dotted",
    fill=False,
)

figure = gl.Figure(x_lim=(-1, 15),y_lim=(-1, 20))
figure.add_elements(rect1, rect2, rect3)
figure.show()

(png, hires.png, pdf)

../_images/shapes-6.png

All Polygon methods can also be used with Rectangle objects.

The Circle Object#

GraphingLib also lets you plot Circles. You can create a Circle by specifying its center point and radius:

circle = gl.Circle(x_center=0, y_center=0, radius=10)

You can customize the appearance of Circles by specifying the following optional parameters: color, line_width, line_style, fill (True or False), and fill_alpha. Here is an example with different styles of Circles:

circle1 = gl.Circle(
    x_center=-4,
    y_center=6,
    radius=10,
    fill_color="C1",
    edge_color="C1",
    line_width=1,
    line_style="solid",
    fill=True,
    fill_alpha=1,
)

circle2 = gl.Circle(
    x_center=4,
    y_center=6,
    radius=7,
    fill_color="C0",
    edge_color="C0",
    line_width=2,
    line_style="dashed",
    fill=True,
    fill_alpha=0.5,
)

circle3 = gl.Circle(
    x_center=0,
    y_center=-4,
    radius=13,
    fill_color="C2",
    edge_color="C2",
    line_width=5,
    line_style="dotted",
    fill=False,
)

# Aspect ratio set to 1 to make the circles look round
figure = gl.Figure(x_lim=(-19, 19), y_lim=(-19, 19), aspect_ratio=1)
figure.add_elements(circle1, circle2, circle3)
figure.show()

(png, hires.png, pdf)

../_images/shapes-8.png

As with Rectangles, all Polygon methods can also be used with Circle objects.

Since Circle objects actually inherit from Polygon, they aren’t perfectly round, and so area and perimeter calculations are approximations. You can get arbitrarily close to the true values by increasing the number of points used to approximate the circle. This can be done by setting the number_of_points parameter when creating the Circle object. The default value is 100, which gives you 99.9% accuracy for the area and even better for the perimeter. Here is an example:

circle = gl.Circle(x_center=0, y_center=0, radius=10, number_of_points=1000)
print(circle.area)
print(circle.perimeter)

The Arrow Object#

GraphingLib also lets you plot Arrows. You can create an Arrow by specifying its start and end points:

arrow = gl.Arrow(pointA=(0, 0), pointB=(10, 10))

You can customize the appearance of Arrows by specifying the following optional parameters: color, width (the line width), head_size, two_sided (True or False), and shrink. The shrink parameter is a float between 0 and 0.5 which shortens the arrow from both ends by the given percentage (0 doesn’t shrink at all, 0.5 makes the arrow disappear completely). Here is an example with different styles of Arrows:

arrow1 = gl.Arrow(
    pointA=(0, 0),
    pointB=(1, 1),
    color="C0",
    shrink=0,  # default, no shrinking
)
arrow2 = gl.Arrow(
    pointA=(1, 0),
    pointB=(2, 1),
    color="C1",
    shrink=0.05,
    two_sided=True,
    head_size=3,
)
arrow3 = gl.Arrow(
    pointA=(2, 0),
    pointB=(3, 1),
    color="C2",
    shrink=0.2,
    two_sided=True,
    width=4,
)

# Create points at the start and end of the arrows (to illustrate the shrinking)
point1 = gl.Point(0, 0, color="C0")
point2 = gl.Point(1, 0, color="C1")
point3 = gl.Point(2, 0, color="C2")
point4 = gl.Point(1, 1, color="C0")
point5 = gl.Point(2, 1, color="C1")
point6 = gl.Point(3, 1, color="C2")

fig = gl.Figure(y_lim=(-0.5, 1.5), x_lim=(-0.5, 3.5))
fig.add_elements(arrow1, arrow2, arrow3)
fig.add_elements(point1, point2, point3)
fig.add_elements(point4, point5, point6)
fig.show()

(png, hires.png, pdf)

../_images/shapes-11.png

The Line object#

It is possible to add lines to figures. Similarly to the Arrow object, simply specify the two end points

line = gl.Line((0, 0), (1, 1))

It is possible to change the width of the line with the width parameter. The capped_line parameter allows you to add perpendicular caps to both ends of the line. The width of those caps can be controlled with the cap_width parameter

# Creating a circle and finding a point at 45 degrees on the circumference
circle = gl.Circle(0, 0, 1, line_width=2, edge_color="C0", fill_color="C0")
center = gl.Point(0, 0, marker_size=50)
point = gl.Point(1, 0, marker_size=50)

# Adding a line to display the radius of the circle
line = gl.Line(
    (0, 0.07), (point.x, point.y + 0.07), capped_line=True, cap_width=1
)
text = gl.Text(0.5, 0.1, r"$R$", font_size=15)

# Display the elements
fig = gl.Figure(size=(5.5, 5))
fig.add_elements(circle, point, line, center, text)
fig.show()

(png, hires.png, pdf)

../_images/shapes-13.png