Building a Tree of Life (version 2)

Phylogenetic tree of randomly selected organisms.

I so liked how the tree of life turned out the last time I tried it, that I did it again this year with a significant improvement in the use of rubber bands.

Students chose organisms and then looked up their classification — Wikipedia quite reliable for this — then they wrote the names down on synchronized chips of colored paper. As usual, they preferentially chose charismatic, mammalian, megafauna, but there was also a squid, and for two people who did not come up with anything themselves, I assigned a plant (elm), and a bacteria (the one that causes strep throat).

The actual color pattern of the chips does not matter, but I used red for Domain, yellow for Kingdom, green for Phylum, pink for Class, red for Order, yellow for Family, green for Genus, and pink for species. The colors repeated, and I liked how that helped organize the pattern of the final result.

In class, using a pin-board, I used push pins to place homo sapiens on the board. I linked the push pins with rubber bands, which makes for a nicer, sharper pattern than using string, and is easier to do.

To get a nice pattern I then asked who had the closest relative to humans. It took a little effort to figure it out, but I decided to go with a degrees-of-separation metric. Basically, I asked them to count up the classification system to see how many levels they’d have to go to get to something their species shared with humans. The closest were at the Class level: mammals.

Then, starting with the students with the lowest separation distance, I had the students come up to the board and add their organism to the growing tree.

Later, during lunch, a student asked me what was the difference between bison and buffalo. I didn’t know, but another teacher pointed out that one was from North America and the other from Africa. So I asked two of my middle schoolers to look up the classification of american bison and water-buffalos, which we subsequently added to the tree, and which got me thinking about how we might use the rate of separation of the two continents to figure out how fast genetic variation develops.

Exponential Growth of Cells

Today I grew, and then killed off, a bunch of bacteria using the VAMP exponential growth model to talk about exponential and logarithmic functions in pre-Calculus. I also took the opportunity to use an exponential decay model to talk about the development of drug resistance in bacteria.

Two cells are reproducing (yellow) during a run of the exponential growth model.

Students had already worked on, and presented to each other, a few bacterial growth problems but the sound and the animation helped give a better conceptual understanding of what was going on.

After watching and listening to the simulation I asked, “What happens to the doubling time?” and one student answered, “It gets shorter,” which seems reasonable but is incorrect. I was able to explain that the doubling time stays the same even though the rate of reproduction (the number of new cells per second) increases rapidly.

Graph showing how the number of cells increases over time.
Switching from growth to decay (half-life of 50 sec).

Then I changed the model from growth to decay by changing the doubling time to a half-life. Essentially this changes the coefficient in the exponent of the growth equation from positive to negative. The growth rate’s doubling time was 100 seconds, but I used a half life of 50 seconds for decay to accelerate things a bit, but still show the persistence of the last of the bugs.

Exponential decrease in cell population/biomass.

The cells died really fast in the beginning, and while there was just one cell was left at the very end, it was pretty clear just how persistent that last cell was; cells were dieing so slowly at the end.

This is similar to what happens when someone takes antibiotics. The typical course lasts for 10 days, but you’ve killed enough of the bacteria to loose the symptoms of sickness after two or three. Those final few that remain are the most resistant to the antibiotic, and if you don’t kill them then, once you stop taking the antibiotic, they’ll start to grow and replicate and you’ll end up sick again with a new, antibiotic-resistant population of bacteria.

I thought that using the VAMP model for the demonstration worked very well. The sound of the cells popping up faster and faster with exponential growth seemed to help amplify the visual effect, and make the whole thing more real. And during the decay phase, having that last cell hang on, seemingly forever, really helped convey the idea that bacteria can be extremely persistent.

Buffalo vs. Bisons: Using their Phylogenetic Classification to Estimate the Rate of Evolution

Classification of american bison and water buffalos.

American bison (Bison bison) are native to North America, while water buffalo (Bubalus bubalis) are from Africa. They are different species, and each are classified in a different genus, however, they belong to the same Family, Bovidae. Since it’s highly unlikely that there was any genetic intermingling after Africa separated from North America, if we can figure out how long ago the two continents were together, we can estimate how long ago their common ancestor lived, and how fast evolution occurs (at least in large mammals).

Continental Rifting

North America is moving away from Africa at an average spreading rate of about 2.5 cm/year, and the continents are about 4550 km apart.

To figure out how long it has been since the continents were together, we need to convert the distance into the same units as the spreading rate and then divide by the rate.

Converting the distance to cm:
 \frac{4550 \text{km}}{1} \times \frac{1000\text{m}}{1\text{km}} \times  \frac{100\text{cm}}{1\text{m}}   = 455,000,000 \text{cm}

Finding the time:
 \frac{455,000,000 \text{cm}}{2.5 \text{cm/year}}= 182,000,000 \;\text{years}

So we get 182 million years.

Evolutionary Rates

Now to get really back-of-the-envelope. If it takes 182 million years to be separated by two levels of classification (the genus and species levels), then it takes approximately 91 million years for each level of classification.

If we extend this backwards up the phylogenetic tree (species –> Genus –> Family –> Order –> Class –> Phylum –> Kingdom ), which is probably illegal, we get a grand total of six levels of classification back to the divergence of the plant and animal kingdoms. That’s 546 million years, which is remarkably close to the time of the first fossil records of complex multi-cellular life, somewhere near the beginning of the Cambrian about 540 million years ago.

The major caveat, however, is that the first phylogenetic step, from Domain to Kingdom took a lot longer than our 91 million year average, since the first life appeared on Earth about 4 billion years ago.

Conclusion

There are lots of issues with this analysis, but the result is curiously coincidental. I’d really appreciate any thoughts on the validity of this particular exercise.

Note:

The spreading happens at the Mid-Atlantic Ridge, which bifurcates the Atlantic. However, if you look at a map of the bathymetry of the North Atlantic, you can see long striations — lines — that show the direction of the tectonic plate motion. The distance the continents moved are best measured along this line.

Cranberries and Climate Change

The problem with global climate change and agriculture not only that it will probably make it harder to grow crops as the continents dry, but also that where you can grow thing will also change as ecological regions shift. Places where there are long traditions of crops such as sugar maples and cranberries will have to adapt, and often, adapting isn’t easy. This article from Marketplace looks at cranberries in Massachusetts.

Programming Agents

An artful spaceship.

For my programming elective, I thought I’d try to get students programming autonomous agents that we could all compile together into some type of game. Since it was, for most of them a first class in programming, this has proven a little too ambitious, and I’ve had to adjust a bit to build up to it.

Step 1: Build a spaceship/vehicle/agent.

A simple ship made of a sphere, ring, and pyramid, with a clear front end (pointed to the left: vector=(1,0,0).
  • We’re using VPython so we can build 3d ships. Students get to exercise their creativity a bit and learn how to place things in 3d co-ordinate space.
  • The ship must have a front end and all the parts must be put into a single frame so the whole thing can be moved as a unit.
  • Although it’s not required, I’ve added in the beginnings of a trail so we can track the motion of the spaceship
from visual import *

f = frame()
r = ring(frame=f, thickness=.25, axis=(0,1,0))
cabin = sphere(frame=f, radius=0.6, color=color.red)
front = pyramid(frame=f, height=1,width=1,length=2, color=color.blue)
trail = curve(pos=[f.pos,])

Step 2: Make the spaceship a class.

  • Putting the spaceship in a separate class, away from the rest of the code, makes it easier to move from one program to another. That means we can import everyone’s ships into a single program at the end.
from visual import *

class spaceship1:

    def __init__(self):

        self.f = frame()
        self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
        self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
        self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
        self.trail = curve(pos=[self.f.pos,])

ss = spaceship1()

Make the spaceship move

  • We’re going to control the movement of the spaceship using the arrow keys. Left and right to turn; up and down to accelerate and decelerate.
  • To allow movement, we’ll put the keyboard controls into an infinite loop, but to allow maximum flexibility (and to show how to use create methods in a class) we’re putting the actual movement in as methods in the class: the turning method is named turn_xz and movement is move_xz since all the motion is going to be restricted in the xz plane for now.
from visual import *

class spaceship1:

    def __init__(self):

        self.f = frame()
        self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
        self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
        self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
        self.trail = curve(pos=[self.f.pos,])

    def turn_xz(self, turn_rate):
        self.f.axis = rotate(self.f.axis, turn_rate, (0,1,0))

    def move_xz(self, speed):
        self.f.pos = self.f.pos + self.f.axis*speed
        self.trail.append(pos=self.f.pos)
                          
ss = spaceship1()
turn = 0.0
speed=0.0

while 1:
    rate(20)  #slows down execution of the loop

    ss.turn_xz(turn)
    ss.move_xz(speed)

    if scene.kb.keys: # event waiting to be processed?
        s = scene.kb.getkey() # get keyboard info

        if s == 'left':
            turn = turn + 0.01
        if s == 'right':
            turn = turn - 0.01

        if s == 'up':
            speed = speed + 0.01
        if s == 'down':
            speed = speed - 0.01

        if s == ' ':
            if turn <> 0:
                turn = 0
            elif speed <> 0:
                speed = 0

Fire missiles

  • We add in missiles by creating a class very similar to the spaceship. For now our missile is just a ball but I’m putting it into a frame anyway in case later on I want it to be a composite object.
  • Since we can fire multiple missiles, in the code I create a list to hold all the missiles.
  • Missiles are fired using the “a” key.
from visual import *

class spaceship1:

    def __init__(self):

        self.f = frame()
        self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
        self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
        self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
        self.trail = curve(pos=[self.f.pos,])

    def turn_xz(self, turn_rate):
        self.f.axis = rotate(self.f.axis, turn_rate, (0,1,0))

    def move_xz(self, speed):
        self.f.pos = self.f.pos + self.f.axis*speed
        self.trail.append(pos=self.f.pos)
          
class missile:
    def __init__(self, axis, pos):

        self.f = frame(axis=axis, pos=pos)
        self.r = sphere(frame=self.f, radius=0.2, color=color.green)
        self.speed = 0.5
        

    def move_xz(self):
        self.f.pos = self.f.pos + self.f.axis*self.speed

                
ss = spaceship1()
turn = 0.0
speed=0.0

missiles = []  #list for missiles

while 1:
    rate(20)  #slows down execution of the loop

    ss.turn_xz(turn)
    ss.move_xz(speed)

    #move missiles
    for i, m in enumerate(missiles):
        m.move_xz()

    if scene.kb.keys: # event waiting to be processed?
        s = scene.kb.getkey() # get keyboard info

        if s == 'left':
            turn = turn + 0.01
        if s == 'right':
            turn = turn - 0.01

        if s == 'up':
            speed = speed + 0.01
        if s == 'down':
            speed = speed - 0.01

        if s == ' ':
            if turn <> 0:
                turn = 0
            elif speed <> 0:
                speed = 0

        #fire missile
        if s == 'a':
            missiles.append(missile(ss.f.axis, ss.f.pos))

Final adjustments

  • Finally, I’m going to put in a boundary, and set it up to delete the missiles if they go out of bounds.
  • I’m also going to set an option so that the scene follows the ship, which makes it easier to keep track of things.
from visual import *

class spaceship1:

    def __init__(self):

        self.f = frame()
        self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
        self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
        self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
        self.trail = curve(pos=[self.f.pos,])

    def turn_xz(self, turn_rate):
        self.f.axis = rotate(self.f.axis, turn_rate, (0,1,0))

    def move_xz(self, speed):
        self.f.pos = self.f.pos + self.f.axis*speed
        self.trail.append(pos=self.f.pos)
                          

class missile:
    def __init__(self, axis, pos):

        self.f = frame(axis=axis, pos=pos)
        self.r = sphere(frame=self.f, radius=0.2, color=color.green)
        self.speed = 0.5
        

    def move_xz(self):
        self.f.pos = self.f.pos + self.f.axis*self.speed

class bounds:
    def __init__(self, boundary_distance):
        self.boundary_distance = boundary_distance
        self.border = curve(pos=[(-boundary_distance,0,-boundary_distance),
                                 (boundary_distance,0,-boundary_distance),
                                 (boundary_distance,0,boundary_distance),
                                 (-boundary_distance,0,boundary_distance),
                                 (-boundary_distance,0,-boundary_distance)])
    def in_bounds(self, pos):
        if ( pos.x < -self.boundary_distance or
             pos.x > self.boundary_distance or
             pos.z < -self.boundary_distance or
             pos.z > self.boundary_distance):
            return false
        else:
            return true
        

ss = spaceship1()
turn = 0.0
speed=0.0
l_track_ship = 1
scene.range=10
scene.forward = (0,-1,0)
missiles = []

boundary_distance = 100
boundary = bounds(boundary_distance)

while 1:
    rate(20)

    if l_track_ship > 0:
        scene.center = ss.f.pos
    
    ss.turn_xz(turn)
    ss.move_xz(speed)

    #move missiles
    del_list = []
    for i, m in enumerate(missiles):
        m.move_xz()

        #delete missile if out of bounds
        if boundary.in_bounds(m.f.pos) == False:
            del_list.append(i)
    for i in del_list:
        missiles[i].f.visible = False
        del missiles[i]
            
    
    #if m <> None:
    #    m.move_xz()

    if scene.kb.keys: # event waiting to be processed?
        s = scene.kb.getkey() # get keyboard info

        if s == 'left':
            turn = turn + 0.01
        if s == 'right':
            turn = turn - 0.01

        if s == 'up':
            speed = speed + 0.01
        if s == 'down':
            speed = speed - 0.01

        if s == ' ':
            if turn <> 0:
                turn = 0
            elif speed <> 0:
                speed = 0

        #fire missile
        if s == 'a':
            missiles.append(missile(ss.f.axis, ss.f.pos))
    

Next steps

Now that we’re cooking with charcoal — we have a functioning program — the next steps will be setting up a target to shoot at, and, if the students are ready, letting them program their ships to move autonomously. If they’re not ready then, as an example, I’ll program some opposition.

Eating Frankenfish

Ian Simpson has an interesting article on the movement to reduce the numbers of the invasive snakehead fish more appealing to restaurants and their customers.

[Snakeheads have] dense, meaty, white flesh with a mild taste that is ideal for anything from grilling to sauteing.

[But] the fish are air breathers that can last for days out of water. Even when gutted and with their throats cut, they gape for breath, said John Rorapaugh, director of sustainability and sales at ProFish, a Washington wholesaler.

“Once they get to mature size, they are on top of the food chain and are ravenous,” he said.

Josh Newhard, an expert on the snakehead with the U.S. Fish and Wildlife Service, said it was too early to say what the snakehead’s long-term impact would be on its invaded environment. … “The potential is really high for them to impact other fish species. The fact that people want to remove them from the system is really good,” he said.

–Simpson (2012): U.S. chefs’ solution for invading Frankenfish? Eat ’em from Reuters via Yahoo! News.

My middle-school students are reading Janet Kagan’s short story, “The Loch Moose Monster” as part of our discussion about genetics, ecology and educational environments. This article makes a nice complement.

Cross-Country

The ridge-top trail.

There’s a trail that runs along the forested ridge above the school. With summer phasing into fall, and the smell of winter in the air, I decided to offer cross-country running as my P.E. option this quarter.

Just getting to the ridge-top is a strenuous jog up a steep slope (note to self: I need to get the geometry students to calculate the slope), especially with the thick, slippery layer of this fall’s accumulated leaves to test the unwary, and I was a little surprised that about half a dozen students actually took me up on it.

Climbing the steep, slippery, leaf-covered slope is not trivial.

Indeed a few more students have accreted onto our group since we started, casualties of the other P.E. options for the most part. But I’d like to think that the beauty of the wooded landscape — brilliant elm and sugar maple leaves littering the ground; crisp, cool air against flushed skin; the fresh, decisive smells in the ridge-top air; the crack an crackle of leaves underfoot — may have also attracted some attention.

I’m looking forward to observing how the slope and forest change with the coming winter.

Autumn sunlight parses the forest.