How I Built A Simple (Horrible) 3D Graphics Engine in python matplotlib - Part 2: Plotting with plt

published-date: 19 Jan 2023 19:49 +0700
categories: dumber-day-by-day python-hijinks
tags: python matplotlib

Posts in This Series


Think of the usual way on how you’d use this library; plotting time series data, market cap analysis, basically anything tubular and qualitative data can be visualized using this kind of representation. Heck even you can add another axis and draw 3D plot with Axes3d.

In previous post I typo’d matplotlib.plt, it should’ve been matplotlib.pyplot (from now on I’ll use the term plt).

We can add values to fields x-axis and y-axis. Any intersecting point will create a vertex, on which a line will traverse through all of these intersecting point.

For example, look at this piece of code:

1import matplotlib.pyplot as plt
2
3x_vals = [1, 2, 3]
4y_vals = [69, 420, 1337]
5
6plt.plot(x_vals, y_vals)
7plt.show()

It will generate the following graph.

Figure 1

But also keep in mind you can loop the values to make a polygon as well!

1import matplotlib.pyplot as plt
2
3x_vals = [1, 2, 3, 2, 1]
4y_vals = [10, 30, 10, -30, 10]
5
6plt.plot(x_vals, y_vals)
7plt.show()

Figure 1

plt on its own is enough to do some graphics programming. But if you’re lazy like me, you can extend plt functionality to the other dimension by adding subplot_kw = {"projection": "3d"} as subplot argument. Following snippet is axes constructor wrapped in a function that will be used for next few examples.

 1def ConstructSubplot3D(x=1, y=1, figsize=(5,5), limit=((-2,2),(-2,2),(-2,2)), elev=60, azim=30, dpi=150):
 2    return plt.subplots(
 3        x, y,
 4        figsize = figsize,
 5        dpi = dpi,
 6        subplot_kw = {
 7        "projection": "3d", 
 8        "proj_type":'ortho', 
 9        "elev":elev, 
10        "azim":azim,
11        "xlim": limit[0],
12        "ylim": limit[1],
13        "zlim": limit[2],
14        }
15    )

with following data we can plot 3D datapoints in 3D!

1x_vals = [1, 2, 3, 2, 1]
2y_vals = [10, 30, 10, -30, 10]
3z_vals = [0,2,5,-2,0]
4
5
6fig, ax = ConstructSubplot3D(limit=((min(x_vals), max(x_vals)), (min(y_vals), max(y_vals)), (min(z_vals), max(z_vals))))
7ax.plot3D(x_vals, y_vals, z_vals)
8fig.show()

Figure 3

You can further modify the elev and azim to change the viewport’s elevation and azimuth respectively.

With just this notion, you can basically build wrappers to make polygon primitives. But all of these only renders the wireframe only. I think there are few other methods that supports faces, textures with UV mapping, etc. but that’d make everything more complicated. And we haven’t talked on how we can apply transformation to these datapoints as well using numpy.linalg. Which hopefully would be in the next post.