This page was generated from docs/tutorials/cga/visualization-tools.ipynb. Interactive online version: Binder badge.

Visualization tools

In this example we will look at some external tools that can be used with clifford to help visualize geometric objects.

The two tools available are:

Both of these can be installed with pip install followed by the package name above.

G2C

Let’s start by creating some objects in 2d Conformal Geometric Algebra to visualize:

[1]:
from clifford.g2c import *
[2]:
point = up(2*e1+e2)
line = up(3*e1 + 2*e2) ^ up(3*e1 - 2*e2) ^ einf
circle = up(e1) ^ up(-e1 + 2*e2) ^ up(-e1 - 2*e2)

We’ll create copies of the point and line reflected in the circle, using \(X = C\hat X\tilde C\), where \(\hat X\) is the grade involution.

[3]:
point_refl = circle * point.gradeInvol() * ~circle
line_refl = circle * line.gradeInvol() * ~circle

pyganja

pyganja is a python interface to the ganja.js (github) library. To use it, typically we need to import two names from the library:

[4]:
from pyganja import GanjaScene, draw
import pyganja; pyganja.__version__
/home/docs/checkouts/readthedocs.org/user_builds/clifford/envs/stable/lib/python3.8/site-packages/pyganja/__init__.py:2: UserWarning: Failed to import cef_gui, cef functions will be unavailable
  from .script_api import *
[4]:
'0.0.15'

GanjaScene lets us build scenes out of geometric objects, with attached labels and RGB colors:

[5]:
sc = GanjaScene()
sc.add_object(point, color=(255, 0, 0), label='point')
sc.add_object(line, color=(0, 255, 0), label='line')
sc.add_object(circle, color=(0, 0, 255), label='circle')
[6]:
sc_refl = GanjaScene()
sc_refl.add_object(point_refl, color=(128, 0, 0), label='point_refl')
sc_refl.add_object(line_refl, color=(0, 128, 0), label='line_refl')

Once we’ve built our scene, we can draw it, specifying a scale (which here we use to zoom out), and the signature of our algebra (which defaults to conformal 3D):

[7]:
draw(sc, sig=layout.sig, scale=0.5)

A cool feature of GanjaScene is the ability to use + to draw both scenes together:

[8]:
draw(sc + sc_refl, sig=layout.sig, scale=0.5)

mpl_toolkits.clifford

While ganja.js produces great diagrams, it’s hard to combine them with other plotting tools. mpl_toolkits.clifford works within matplotlib.

[9]:
from matplotlib import pyplot as plt
plt.ioff()  # we'll ask for plotting when we want it

# if you're editing this locally, you'll get an interactive UI if you uncomment the following
#
#    %matplotlib notebook

from mpl_toolkits.clifford import plot
import mpl_toolkits.clifford; mpl_toolkits.clifford.__version__
/home/docs/checkouts/readthedocs.org/user_builds/clifford/envs/stable/lib/python3.8/site-packages/traitlets/traitlets.py:3030: FutureWarning: --rc={'figure.dpi': 96, 'savefig.transparent': True} for dict-traits is deprecated in traitlets 5.0. You can pass --rc <key=value> ... multiple times to add items to a dict.
  warn(
[9]:
'0.0.3'

Assembling the plot is a lot more work, but we also get much more control:

[10]:
# standard matplotlib stuff - construct empty plots side-by-side, and set the scaling
fig, (ax_before, ax_both) = plt.subplots(1, 2, sharex=True, sharey=True)
ax_before.set(xlim=[-4, 4], ylim=[-4, 4], aspect='equal')
ax_both.set(xlim=[-4, 4], ylim=[-4, 4], aspect='equal')

# plot the objects before reflection on both plots
for ax in (ax_before, ax_both):
    plot(ax, [point], color='tab:blue', label='point', marker='x', linestyle=' ')
    plot(ax, [line], color='tab:green', label='line')
    plot(ax, [circle], color='tab:red', label='circle')

# plot the objects after reflection, with thicker lines
plot(ax_both, [point_refl], color='tab:blue', label='point_refl',  marker='x', linestyle=' ', markeredgewidth=2)
plot(ax_both, [line_refl], color='tab:green', label='line_refl', linewidth=2)

fig.tight_layout()
ax_both.legend()

# show the figure
fig
[10]:
../../_images/tutorials_cga_visualization-tools_19_0.svg

G3C

Let’s repeat the above, but with 3D Conformal Geometric Algebra. Note that if you’re viewing these docs in a jupyter notebook, the lines below will replace all your 2d variables with 3d ones

[11]:
from clifford.g3c import *
[12]:
point = up(2*e1+e2)
line = up(3*e1 + 2*e2) ^ up(3*e1 - 2*e2) ^ einf
circle = up(e1) ^ up(-e1 + 1.6*e2 + 1.2*e3) ^ up(-e1 - 1.6*e2 - 1.2*e3)
sphere = up(3*e1) ^ up(e1) ^ up(2*e1 + e2) ^ up(2*e1 + e3)
[13]:
# note that due to floating point rounding, we need to truncate back to a single grade here, with ``(grade)``
point_refl = homo((circle * point.gradeInvol() * ~circle)(1))
line_refl = (circle * line.gradeInvol() * ~circle)(3)
sphere_refl = (circle * sphere.gradeInvol() * ~circle)(4)

pyganja

Once again, we can create a pair of scenes exactly as before

[14]:
sc = GanjaScene()
sc.add_object(point, color=(255, 0, 0), label='point')
sc.add_object(line, color=(0, 255, 0), label='line')
sc.add_object(circle, color=(0, 0, 255), label='circle')
sc.add_object(sphere, color=(0, 255, 255), label='sphere')
[15]:
sc_refl = GanjaScene()
sc_refl.add_object(point_refl, color=(128, 0, 0), label='point_refl')
sc_refl.add_object(line_refl.normal(), color=(0, 128, 0), label='line_refl')
sc_refl.add_object(sphere_refl.normal(), color=(0, 128, 128), label='sphere_refl')

But this time, when we draw them we don’t need to pass sig. Better yet, we can rotate the 3D world around using left click, pan with right click, and zoom with the scroll wheel.

[16]:
draw(sc + sc_refl, scale=0.5)

Some more example of using pyganja to visualize 3D CGA can be found in the interpolation and clustering notebooks.

mpl_toolkits.clifford

The 3D approach for matplotlib is much the same. Note that due to poor handling of rounding errors in clifford.tools.classify, a call to .normal() is needed. Along with explicit grade selection, this is a useful trick to try and get something to render which otherwise would not.

[17]:
# standard matplotlib stuff - construct empty plots side-by-side, and set the scaling
fig, (ax_before, ax_both) = plt.subplots(1, 2, subplot_kw=dict(projection='3d'), figsize=(8, 4))
ax_before.set(xlim=[-4, 4], ylim=[-4, 4], zlim=[-4, 4])
ax_both.set(xlim=[-4, 4], ylim=[-4, 4], zlim=[-4, 4])

# plot the objects before reflection on both plots
for ax in (ax_before, ax_both):
    plot(ax, [point], color='tab:red', label='point', marker='x', linestyle=' ')
    plot(ax, [line], color='tab:green', label='line')
    plot(ax, [circle], color='tab:blue', label='circle')
    plot(ax, [sphere], color='tab:cyan')  # labels do not work for spheres: pygae/mpl_toolkits.clifford#5

# plot the objects after reflection
plot(ax_both, [point_refl], color='tab:red', label='point_refl', marker='x', linestyle=' ', markeredgewidth=2)
plot(ax_both, [line_refl.normal()], color='tab:green', label='line_refl', linewidth=2)
plot(ax_both, [sphere_refl], color='tab:cyan')

fig.tight_layout()
ax_both.legend()

# show the figure
fig
/home/docs/checkouts/readthedocs.org/user_builds/clifford/envs/stable/lib/python3.8/site-packages/IPython/core/pylabtools.py:134: MatplotlibDeprecationWarning: The 'renderer' parameter of do_3d_projection() was deprecated in Matplotlib 3.4 and will be removed two minor releases later.
  fig.canvas.print_figure(bytes_io, **kw)
/home/docs/checkouts/readthedocs.org/user_builds/clifford/envs/stable/lib/python3.8/site-packages/IPython/core/pylabtools.py:134: MatplotlibDeprecationWarning:
The M attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use self.axes.M instead.
  fig.canvas.print_figure(bytes_io, **kw)
[17]:
../../_images/tutorials_cga_visualization-tools_32_1.svg

Some more example of using mpl_toolkits.clifford to visualize 3D CGA can be found in the examples folder of the mpl_toolkits.clifford repositiory, here.