sPYnning icon indicating copy to clipboard operation
sPYnning copied to clipboard

Source code for animating a spinning globe, consisting of hexagons.

sPYnning

Source code for animating a spinning globe, consisting of hexagons. This can be used to generate images similar to the ones in the original twitter tweet. Below are some images that are created in the Jupyter notebook.

For more images and GIFs, check out https://www.camminady.org/spinningglobe

Note that this code is closely linked to the PlatonicSolidsQuadratures repository which allows for an easier handling of quadrature related aspects.

How To?

Locally

Clone the repository and run through the cells of visworld.ipynb found here.

If you encounter an issue with mpl_toolkits (I did), this link might help. To deal with that issue, the Google Colab version additionally runs

sudo apt-get install libgeos-dev
sudo pip3 install https://github.com/matplotlib/basemap/archive/master.zip

Google Colab

I ported the Jupyter notebook to Google Colab. In the process, I had move the helpers.py file in the notebook.

Open In Colab

Note that the Colab notebook is already outdated and contains only the initla animations, no diffusion or Game of Life.

Globe

nq = 2252
quadrature = getquadrature(nq)
# plot the earth 
colors  = color_land(quadrature)
myplot(colors,quadrature,"earth.png")

Globe

Country colored

# higher resolution to plot countries
nq = 7292
quadrature = getquadrature(nq)
colors  = color_country(quadrature)
myplot(colors,quadrature,"earth_country.png")

Globe

Animated GIF

nq = 7292
quadrature = getquadrature(nq)
colors  = color_land(quadrature)

frames = []
nframes = 20 # the more, the slower 
for i,angle in enumerate(np.linspace(0,360,nframes)[:-1]):
    print(i,end=",")
    frames.append(myplot(colors,quadrature,"tmp.png",frameid = i, angle1=30,angle2=angle))

gif.save(frames,"spinning_earth.gif")

Globe

Diffusion equation (only faked, not for scientific purposes)

We need an update rule for each time step.

def diffusion(c,nextc,gamma = 0.2):
    # Not really spherical diffusion
    # because I ignore the cell size,
    # but an approximation.
    return c+gamma*(np.sum(nextc) -len(nextc)*c)

Then we can update the states in every iteration

# pick the number of cells on the globe from this list
# [92, 492, 1212, 2252, 3612, 5292, 7292, 9612, 12252, 15212]
nq = 9612
quadrature = getquadrature(nq)

# +1 or -1 if center of hexagon is land or not 
states = np.array([0.7 if l else -1.0 for l in get_land(quadrature)])
# if there were an eleveation profile of the earth, 
# I could insert that instead of states

frames = []   # list of frames to append to 
nframes = 200 # number of frames 
frequency = 1 # frequency with which to update the states

# make camera move around the globe and up and down
angles1 = 0.2*np.degrees( np.sin(np.linspace(0,5*2*np.pi,nframes+1)[:-1]))
angles2 = np.linspace(0,3*360,nframes+1)[:-1]

# specify the update rule
updaterule = diffusion

for i,(angle1,angle2) in enumerate(zip(angles1,angles2)):
    
    # Map from states to color 
    cmap = matplotlib.cm.get_cmap('terrain') 
    colors = [cmap(s) for s in states]

    frames.append(myplot(colors,quadrature,f"PNG/{i}.png",i,angle1=angle1,angle2=angle2))
    
    # update states according to rule 
    if i%frequency == 0:
        states = applyupdate(quadrature,updaterule,states)
     
    print(i+1,end= "," if i<nframes-1 else ". Done!")
gif.save(frames, "diffusion.gif", duration = 100)

Diffusion

Game of Life

We gain need an update rule. A cell's state is updated based upon the adjacent neighbours. Here you can be creative.

def gameoflife(c,nextc):
    # update the cell c based upon the neighbours nextc
    # c is true => cell alive
    # c is fale => cell dead 
    
    n = len(nextc) # is mostly 6 but for some points 5 
    nalive = sum(nextc)
    if not(c) and nalive in [1,2]:
        return True
    
    if c  and nalive in [3,4,5,6]:
        return False

    # Else, nothing changed
    return c

Then create the animation.

# pick the number of cells on the globe from this list
# [92, 492, 1212, 2252, 3612, 5292, 7292, 9612, 12252, 15212]
nq = 5292
quadrature = getquadrature(nq)

# True or False if center of hexagon is land or not 
states = np.random.rand(nq)<0.01

frames = []   # list of frames to append to 
nframes = 100 # number of frames 
frequency = 5 # frequency with which to update the states

# make camera move around the globe and up and down
angles1 = np.degrees( np.sin(np.linspace(0,2*np.pi,nframes+1)[:-1]))
angles2 = 30+0*np.linspace(0,3*360,nframes+1)[:-1]

# specify the update rule
updaterule = gameoflife

for i,(angle1,angle2) in enumerate(zip(angles1,angles2)):
    
    # Map from states to color 
    colors = ["tab:green" if s else "k" for s in states]

    frames.append(myplot(colors,quadrature,f"PNG/{i}.png",i,angle1=angle1,angle2=angle2))
    
    # update states according to rule 
    if i%frequency == 0:
        states = applyupdate(quadrature,updaterule,states)
     
    print(i+1,end= "," if i<nframes-1 else ". Done!")
gif.save(frames, "gol.gif", duration = 100)

Game of Life