David Patrick McKenzie

Historian working in academic, digital, and public forms

Author: David McKenzie (page 5 of 10)

Short tutorial: Cleaning up a Google Book for text mining

This post has now been cross-posted to the class blog. Any future updates, as of 12/17/2012, will appear there.

Lesson Goals & Reasons

Why?

Google Books has increasingly become one of the main repositories of textual sources for historians and other humanities scholars. As many have discussed, it has its issues. Nonetheless, it remains a valuable place to gather texts for those interested in text mining–provided we clean the text first.

Why is this important? You want your text mining to give you accurate results. The example that I am using, a volume of the Diplomatic Correspondence of the Republic of Texas, exemplifies some of these issues. When I ran the text file through Voyant, Here’s what happened:

As you can see, “Digitized” and “Google” appeared as two of the most common words! Presumably Texas diplomats in the 1830s and 1840s would not have been writing about digitization or about Google. Additionally, the words United and States popped up frequently–because the top of each page included “Correspondence with the United States” for a large part of the book. I want to know if the words “United States” do indeed show up frequently otherwise, along with other important ideas, like words having to do with annexation. Using text mining techniques could help contribute to an understanding of Texas’s diplomatic policies when it was a republic–but only if we can run those features on an accurate copy of the correspondence.

Goals

This lesson will use a sample Google Books document with some of the issues that tend to accompany texts from that repository. You will clean that document–removing some of the specific Google Books formatting, then going through basic steps to prepare it for text mining. Some of these principles will be applicable for many different books.

You will need:

  • A Google Books document, preferably in text format. I downloaded this one from the Internet Archive. Otherwise, you can convert a Google Books PDF to text.
  • A text editor to create Python scripts.
  • The ability to execute Python. I personally like to use Komodo Edit because it includes the ability to execute a Python script right in your window. Programming Historian 2 has a method for setting that up. You can also, of course, test your scripts using the command line.

What Will You Do?

In this tutorial, we will create a Python script to:

  • Download the text file of a Google Book from Archive.org.
  • Strip out page numbers and titles on the tops of pages
  • Remove the introductory portions of the file & strip out the HTML.
  • Strip out “Digitized by Google”.
  • Save the file to your drive

Begin the script and get the document

To start, we’ll begin our Python script in KomodoEdit. Open KomodoEdit and save a new file as “tx-dip-corr.py” (or whatever you’d like to, for whatever you will be using).

First we want to give our script access to a couple of different Python libraries–one that deals with getting documents from the Internet, and one that gives us access to regular expressions (which will be explained later). To access those, we use the “import” command:

import urllib2
import re

Next, we want to open a file from the web. To do so, let’s create a variable, called “url,” and give it the web address of the item we want to open. So type:

url = ""

Then we want to get our URL, which will go into the quotation marks.

Many of the out-of-copyright works that Google has scanned have been uploaded to the Internet Archive and are available in multiple formats. In this case, we want to use the text version. For this tutorial, I am using a volume of the Diplomatic Correspondence of the Republic of Texas from the Internet Archive.

Right-click on the link that says “Full Text” and copy the URL. This is the file we will be using. Paste the URL between the quotation marks. So, you will now have:

url = "http://archive.org/stream/diplomaticcorre33statgoog/diplomaticcorre33statgoog_djvu.txt"

That only gave us the URL for opening the file, though. Next we want actually to open it. First we have it opened, then we have it read. Python makes us do this in two lines:

response = urllib2.urlopen(url)
txt = response.read()

If you want to use a file you have already downloaded, this lesson from Programming Historian 2 shows how to open a file already on your computer.

Strip out page numbers and titles on the tops of pages

The title of the book or section, plus the page number, was captured in the scan–not to mention digitization information:

Here is what it looks like in the text:

This could throw off our text mining results, so let’s get rid of it! We want to strip out the page numbers and titles on the tops of pages. Unfortunately, the scan of this book was not the best (to put it mildly), and so the text on the top of each page rendered differently. It should say, on one side, “[page number] American Historical Association” (because the book was published by the American Historical Association). On the other side, it should say, “Correspondence with [country]. [page number].” As you can see, it doesn’t do that; the only consistency we get is that the page number is at the beginning or ending of the line.

Luckily, we can use regular expressions to find these lines and get rid of them.

We begin with setting a variable–let’s call it “txt”–for holding the text. We set it empty–for now:

txt = ""

Next we have the program go through the file looking for what we want it to find. To do that, we set up a variable that we’ll call “line”:

for line in response:

Then we set up a search, using regular expressions, to find the one consistency that we identified:

for line in response:
    matchObj = re.search("(^[\s]*[0-9]+\s.*)|(.*\s[0-9]+[\s]*$)", line)

We are creating a variable, “matchObj,” that is searching the whole text line-by-line, using regular expressions (“re.search”). My classmate Laura explains more about regular expressions in her tutorial. Some explanation for what is happening here: We are parsing through the document and finding instances where either a line begins (indicated by ^) with a number (indicated by [0-9]) or ends (indicated by $) with a number (again, [0-9]). The “|” splitter gets the program to do either one or the other. It also includes any words (indicated by *) and any spaces and other white space (indicated by “\s”, which would typically stop the search). The “+”, meanwhile, indicates that we want to find the previous item (e.g., numbers) more than once. Here is a complete listing of regular expressions and what they do.

But, all that this has done is search through the text. We then need to tell it what to do. For that, we use an “if…else” statement. First the if:

for line in response:
    matchObj = re.search("(^[\s]*[0-9]+\s.*)|(.*\s[0-9]+[\s]*$)", line)
    if matchObj is not None:
        pass

Here, we are telling the program that if the search results yield something, then that line is not to be saved; that is the equivalent to deleting it from the file.

Next, we want to make sure that every other line is coming through. So we tell it:

for line in response:
    matchObj = re.search("(^[\s]*[0-9]+\s.*)|(.*\s[0-9]+[\s]*$)", line)
    if matchObj is not None:
        pass
    else:
        txt += line

This is saying that if something the line does not come up in the search, it is added to the text to be saved to our computer. Now, those page headers are all gone!

Remove the introductory portions of the file & strip out the HTML

Diplomatic Correspondence of the Republic of Texas is a compilation of primary source documents. As such, for our purposes we are not interested in parts that are not the primary source documents; thus, we do not want the introductory material to the volume, not to mention Google’s information about it. This particular file also has information from Archive.org on the top.

Open the file in your web browser. Scroll to where the primary sources begin–in this case, it’s a line that says “CORRESPONDENCE HITHERTO UNPUBLISHED.” Note this, as it will be important.

Write the function

Now we are going to write a function to grab the parts of the file that we want and strip out any HTML in it, leaving us with text. We begin by naming our function:

def stripTags(pageContents):

First, in our function, we want to define where to start grabbing the file. Remember where we noted the text where we wanted to begin? Now we see it again:

def stripTags(pageContents):
    startLoc = pageContents.find("CORRESPONDENCE HITHERTO UNPUBLISHED.")
    pageContents = pageContents[startLoc:]

This tells the program to go through that document and find the line we previously identified, and set that as the starting location. Then, it takes everything from that point forward as the text that we want. In other words, it doesn’t send over the beginning, introductory text.

Next, we want to strip out the HTML. We do this with an “if…else” statement. All HTML in the file, of course, is found between “<>.” So we want to take anything between those symbols and remove it.

To do this, we will use the integers 0 and 1 for what is inside and outside the “<>.” So, we define the variable “inside” and set up an empty list for the variable “cleantext” (which will hold our cleaned-up text). Here is the code:

def stripTags(pageContents):
    startLoc = pageContents.find("CORRESPONDENCE HITHERTO UNPUBLISHED.")
    pageContents = pageContents[startLoc:]

    inside = 0
    cleantext = ''

After this, we want to search for the “<>” and remove them, plus anything inside. We do this with an if…else statement:

def stripTags(pageContents):
    startLoc = pageContents.find("CORRESPONDENCE HITHERTO UNPUBLISHED.")
    pageContents = pageContents[startLoc:]

    inside = 0
    cleantext = ''
    for char in pageContents:
        if char == '<':
            inside = 1
        elif(inside == 1 and char == '>'):
            inside = 0
        elif inside == 1:
            continue
        else:
            cleantext += char  
    return cleantext

After all of that, we now have our cleaned text. Sort of.

Execute the function

We now need to execute our function on the text we’ve retrieved from the Internet.

Let’s call the variable for the executed function “ctext” for “cleaned text.” We have that variable execute that function on the text (defined as txt) downloaded:

ctext = stripTags(txt)

Next, we’ll clean some other results of the digitization out of the text.

Strip out “Digitized by Google”

As you scroll through the file, you’ll notice there are parts that repeat. In Google Books, each page image gets “Digitized by Google” placed on it. When whoever created the plain text file from Diplomatic Correspondence of the Republic of Texas did the OCR, that portion was caught.

Luckily, it’s rather easy to strip out the “Digitized by Google” lines using Python’s replace function. We set a variable to house the text without that portion–let’s call it “stripGoogle”:

stripGoogle =

Next, we get the source of the text–in this case, the variable we just created to execute the stripTags function. So we tell stripGoogle to take that variable:

stripGoogle = ctext

Unfortunately, those words exist on separate lines, so we have to replace them separately. We append this to the end of “ctext”–we are replacing the text found in “ctext.” We replace this with nothing, indicated by the quotation marks with nothing between them:

stripGoogle = ctext.replace("Digitized by","").replace("Google","")

Save the file to your drive

Now that the file is cleaned, we’re prepared to commit it to our hard drive. From there, we can take the file into tools like Voyant, or use it for text mining.

First, we want to create the file, which we’ll call “tx-dip-corr.txt.” So we set a variable–we’ll call it “f”–to create a blank file of that title:

f = open('tx-dip-corr.txt','w')

Next, we want to write the final result of our manipulations–which we contained in a variable called “stripGoogle” (this will change as I figure out the regular expressions for the last part!)–into the file. We do this with the write function:

f = open('tx-dip-corr.txt','w')
f.write(stripGoogle)

Finally, we close that file at the end of our script:

f = open('tx-dip-corr.txt','w')
f.write(stripGoogle)
f.close

Wrapping it up

Unfortunately, this tutorial doesn’t deliver you a perfectly clean copy of the Diplomatic Correspondence of the Republic of Texas. A lot of the OCR is pretty bad, so some manual cleanup will still be needed. Some of the OCR errors are consistent, so a simple find/replace in a text editor might help–or even a simple Python script.

In the end, the cleaned version still shows “United” and “States” as two of the most common words. So, one could do even more with this. Nonetheless, we have removed some of the issues:

This tutorial has shown how to strip out some of the more common issues with the text of a Google Book. Once you execute the script, you will have the file saved on your computer. Enjoy the text mining! For your reference, here is the entire script, including comments about what does what:

#tx-dip-corr.py
#import libraries
import urllib2
import re

#open file from the web
url = "http://archive.org/stream/diplomaticcorre33statgoog/diplomaticcorre33statgoog_djvu.txt"
response = urllib2.urlopen(url)  # open('C:\\temp\\diplomaticcorre33statgoog_djvu.txt', 'r') 

# build up txt without page numbers
txt = ""
for line in response:
    matchObj = re.search("(^[\s]*[0-9]+\s.*)|(.*\s[0-9]+[\s]*$)", line)
    if matchObj is not None:
        pass
    else:
        txt += line

#function to strip the introductory portion and HTML tags
def stripTags(pageContents):
    startLoc = pageContents.find("CORRESPONDENCE HITHERTO UNPUBLISHED.")
    pageContents = pageContents[startLoc:]

    inside = 0
    cleantext = ''
    for char in pageContents:
        if char == '<':
            inside = 1
        elif(inside == 1 and char == '>'):
            inside = 0
        elif inside == 1:
            continue
        else:
            cleantext += char  
    return cleantext

#now execute the function
ctext = stripTags(txt)

#strip out "Digitized by Google" through the whole file
stripGoogle = ctext.replace("Digitized by","").replace("Google","")

#create the file and write results to it
f = open('tx-dip-corr.txt','w')
f.write(stripGoogle)
f.close

I am eternally grateful to my friend Kelvin Pan for helping me resolve some issues that arose as I tried to figure this out, and to my professor, Fred Gibbs, for his helpful comments.

Clio 3 Long (enough, I hope) Tutorial: Creating a MySQL Database Listing in Your WordPress Site

Note: I have cross-posted this on the class blog. Should any changes be made, they will appear on that site in the future.

Lesson Goals & Reasons

Goals

In this lesson, you will learn how to create a listing of data from a MySQL database, and have it display in WordPress.

You will need:

  • A WordPress site (often used for a blog), hosted on your own server. In other words, not a blog/site hosted on WordPress.com.
  • A MySQL database, separate from your WordPress site.
  • A text editor, such as Komodo Edit or TextWrangler. These are available for free.
  • A FTP client, such as CyberDuck, for connecting to your server.

You will do the majority of the editing in the separate text editor; you may also use WordPress’s native interface.

Why?

Many historians have own own blogs–perhaps even as part of our own websites–and separate databases that we use for research. This tutorial will show you how to display the data from your MySQL database on your WordPress site, so that you don’t need a separate site for that purpose. In the long run, this will save you time, as you won’t have to develop a separate CSS for your database listing (and other related pages). Your listing will simply follow the style of your WordPress site.

This tutorial is for those who have an existing MySQL database and would like not to have to create a custom website for displaying, modifying, and/or querying the data. In other words, you can make your database pages follow the style of your WordPress template and live in your already-existing website.

As you may know, WordPress offers a plethora of plugins. There are two (here and here) that offer the option of integrating a MySQL database into your WordPress. What they do, however, is require you to copy your already-existing database into WordPress’s MySQL database. Doing this increases the possibility of error–for instance, if you make an alteration to your data and click the wrong place, you may break something in WordPress. So, we want to keep our MySQL database separate from our WordPress database; in this tutorial, we are simply using WordPress to display data from your MySQL database.

What Will You Do?

This tutorial has four parts:

  • Understanding WordPress: Providing a basic explanation of relevant parts of WordPress and how it works.
  • Creating the Connection: How to connect your separate database into WordPress.
  • Creating a New Template: How to create a page to hold your listing.
  • Creating Your Listing: How to list the contents of your database, right in your WordPress page.

Understanding WordPress

Basics

WordPress is a content management system. Many historians, in particular, use it to host a blog; indeed, that’s its original function. But WordPress is also a great system to use for an entire website.

WordPress divides into two basic “units”: posts and pages. To make a technical explanation short, posts are your typical blog posts. Pages, meanwhile, act like the static pages you find on any website. In this tutorial, you will create custom pages to display the data from your MySQL database.

WordPress, like many other content management systems, is coded in PHP. In fact, it is connected to its own MySQL database; anything you put into it–a page, a post, a picture–is stored in a specified spot within WordPress’s database. Each page or post fishes out that content and displays it.

Themes

A theme is what controls the appearance of your WordPress site. Each theme (of which there are, now, literally thousands) contains several PHP files for different parts of WordPress. There are several page templates within each WordPress theme. In this tutorial, we will duplicate and edit a page template.

An important note: If you haven’t done any modifications before to your WordPress template, you should create a child theme. Here is how to do that and why it’s important. Any pages that we create here will be saved into the child theme.

We will be working in the folders for your parent and child themes: duplicating files from your parent theme folder into your child theme, and making changes there. To find your theme folders, open your FTP software and navigate to the folder where you have your installation of WordPress. The file structure of WordPress is the same for each installation. The themes can be found under wp_content, then themes. The folder holding your parent theme houses the different page files for that theme.

Creating the connection

In this tutorial, we will just be making database listing. However, you may, in the long run, want to use your WordPress site for multiple functions related to your MySQL database. For example, you may want to have a data entry form. Or you may want to have a page where you, or your users, can query the database. As such, in this section we are going to set up a function that will allow you to connect to your separate MySQL database with just one line of code, in any page.

Create a child theme Functions.php file

Each WordPress theme contains a file called functions.php. This file is essential to WordPress. A function is a set of code in PHP containing a series of commands. Generally, you want to create functions for a sequence of commands you may use frequently. WordPress stores all of its functions–called up throughout your site–in functions.php.

We will set up a separate functions.php file for our child theme. This will augment, but not alter, the functions.php file that came installed with your theme. The reason: less room to break the entire site by accidentally altering or deleting an essential function.

Create your function

Create a new file called “functions.php,” and save it in your child theme folder. Open that file.

Now we will create a function to connect to our database. Begin with the basic opening and closing command for PHP:

 <?php

?>

All of our commands will be within those brackets. Next, create the basis for the function. Let’s call it open_mysql_db:

 <?php 
function open_mysql_db() {

}
?>

As you can see, PHP calls on us to use parentheses after the name of the function. All of our commands to execute the function, meanwhile, go within the curly braces.

Next, within the function, create a PHP variable–many of the tutorials I’ve seen use $mysqli for this purpose, so I’ve used it here. With this variable, you tell your file to connect to your MySQL database, located separately on your server. You input the address for your database, your login name, your password, and the specific database you are using. Make sure to put those things in single quotation marks, like below:

<?php 
function open_mysql_db() {
$mysqli = new mysqli('address of database', 'username', 'password', 'database name'); 
}
?>

Finally, we want to know if the connection does not work. This code will tell us:

<?php
  function open_mysql_db() {
    $mysqli = new mysqli('address of database', 'username', 'password', 'database name'); 
		
    // check connection 
    if (!$mysqli)
    throw new Exception('Could not connect to database');
    else
    return $mysqli;
  };
?>

What does this do? Essentially, it tests the connection (represented by the variable $mysqli), and gives you an error message if it doesn’t connect.

Now that we have our function defined, save and close your functions.php file. This function will now be available for any part of your site to use!

Creating a New Template

Now we will create the page to house your database listing. We will do this in a text editor (such as TextWrangler), but we can also do it in WordPress’s editor on your site. For this tutorial, I’m using the text editor, because it uses colors to help us understand the code we are inputting, and even indicates where we need to close brackets!

Create a new template

To create the page to display your data, you can pick any of the pre-existing page templates. Each page lives in the directory for your parent theme. In the parent theme directory, find the template you wish to use. Copy (do not move!) it into your child directory. Rename the duplicate file; for this tutorial, let’s call it “database_list.php.” Open that file in your text editor.

This next portion will vary depending on the theme. In some themes, at the very top of the page you will see a line saying “Template Name:”. If it is there, on this line input the name you want to call the template. This is important, as this is how you will choose this particular template for your page. For what we’re doing in this tutorial, let’s call our template “Database Listing.”

If the code is not there, insert the following at the top of the file–some themes offer this option, some do not:

<?php /**  
* Template Name: Database Listing  
*/ ?>

Connect to your MySQL database

Every WordPress page template has similar elements, the most important being “the_content.” This displays the content that you create for a particular page in WordPress’s scheme. Look for this line:

<?php the_content(); ?>

You will place everything that you need to for your database listing beneath this line, and above everything else–especially this line:

 <?php endwhile; ?> 

The reason? The key to how WordPress does this is a concept called “The Loop.” Basically, this is what tells tells WordPress to continue fishing content out of the database to display. Without The Loop, you could only display one blog post at a time. You can learn more about The Loop here and here. For our purposes, the most important part to know: any code that we add to our pages must be above that particular line, which is what makes The Loop stop running. If your code is below the line, WordPress will not know to use it, and thus will not.

Now, we tell the template to run the function that we just created. To do that, we give the function a variable. In this case, we’ll use “$conn” for “connection”–you can use whatever variable you want, as long as you remember it and use the same one! Insert this line:

<?php $conn = open_mysql_db(); ?>

Each time that variable is used, WordPress will know to run the function.

Creating Your Listing

Now we are ready to create our database listing. We will create a table using basic HTML commands–except that we are telling it to display the contents of our database. For purposes of this tutorial, we’ll use a database with four fields (called “field1,” “field2,” “field3,” and “field4″–creative, I know) in a table called “table.”

Query the database

We begin, as always, with our opening and closing PHP brackets:

<?php

?>

Now connect to the database and select the fields that we want to display in our listing. We start with an if-else statement. Essentially, we are telling the template to display the table if it can connect and get results from the query. Otherwise, it will tell you that there is an error:

<?php
// get the records from the database
if ()
  {

  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Next, we give the query a variable–“$result” in this case–and run the query using regular MySQL commands:

<?php
// get the records from the database
if ($result = $conn->query("SELECT field1,field2,field3,field4 FROM table;"))
  {

  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Now, within our curly braces after we query the database, we include another if-else statement. If the query works, we want to display our results. Otherwise, it displays an error message. So first, set up the if-else statement:

<?php
// get the records from the database
if ($result = $conn->query("SELECT field1,field2,field3,field4 FROM table;"))
  {
    // display records if there are records to display
    if ($result->num_rows > 0)
      {

      }
    // if there are no records in the database, display an alert message
    else
      {
        echo "No results to display!";
      }
  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Now give a style to your table:

<?php
// get the records from the database
if ($result = $conn->query("SELECT field1,field2,field3,field4 FROM table;"))
  {
    // display records if there are records to display
    if ($result->num_rows > 0)
      {
        // display records in a table
        echo "<table border='1' cellpadding='10'>";

        echo "</table>";

      }
    // if there are no records in the database, display an alert message
    else
      {
        echo "No results to display!";
      }
  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Next, set up the headers for your table:

<?php
// get the records from the database
if ($result = $conn->query("SELECT field1,field2,field3,field4 FROM table;"))
  {
    // display records if there are records to display
    if ($result->num_rows > 0)
      {
        // display records in a table
        echo "<table border='1' cellpadding='10'>";

          // set table headers
          echo "<tr><th>Field 1:</th><th>Field 2:</th><th>Field 3:</th><th>Field 4:</th></tr>";

        echo "</table>";

      }
    // if there are no records in the database, display an alert message
    else
      {
        echo "No results to display!";
      }
  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Next, we query the database and pull out the data from each record (row) in the database. We set up a while statement–while each row of data is being fetched, will be put into the table. Begin with the while statement:

<?php
// get the records from the database
if ($result = $conn->query("SELECT field1,field2,field3,field4 FROM table;"))
  {
    // display records if there are records to display
    if ($result->num_rows > 0)
      {
        // display records in a table
        echo "<table border='1' cellpadding='10'>";

        // set table headers
          echo "<tr><th>Field 1:</th><th>Field 2:</th><th>Field 3:</th><th>Field 4:</th></tr>";
          while ($row = $result->fetch_object())
            {

            }
        echo "</table>";

    }
  // if there are no records in the database, display an alert message
  else
    {
      echo "No results to display!";
    }
  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Finally, we put in our table, which will display each record of our database. To do this, we use the HTML code to create rows of the table. Then for each row, we input the variable “$row”, then “->”, then the name of each field. This tells the file to cycle through all of the records (i.e., each row) of the database until there are no more. Here is the code:

<?php
// get the records from the database
if ($result = $conn->query("SELECT field1,field2,field3,field4 FROM table;"))
  {
    // display records if there are records to display
    if ($result->num_rows > 0)
      {
        // display records in a table
        echo "<table border='1' cellpadding='10'>";

          // set table headers
          echo "<tr><th>Field 1:</th><th>Field 2:</th><th>Field 3:</th><th>Field 4:</th></tr>";
            while ($row = $result->fetch_object())
              {
                // set up a row for each record
                echo "<tr>";
                  echo "<td>" . $row->field1 . "</td>";
                  echo "<td>" . $row->field2 . "</td>";
                  echo "<td>" . $row->field3 . "</td>";
                  echo "<td>" . $row->field4 . "</td>";
                echo "</tr>";
              }
        echo "</table>";

      }
    // if there are no records in the database, display an alert message
    else
      {
        echo "No results to display!";
      }
  }
// show an error if there is an issue with the database query
else
  {
    echo "Error: " . $conn->error;
  }
?>

Now you have your template, which will include your listing. But we’re not done yet; all we’ve done is create a template for your eventual page.

Create a new page for the data

Next we will create the actual page for displaying this data.

On the left side of your WordPress dashboard, go to Pages>Add New. Name the page whatever you would like, e.g., “[Database Name]: Listing.” Next, write any explanatory text you would like in the content box. This will go above your listing. Here is what the interface looks like:

Now, we want to connect this page to its template. On the right side, you see a box for “Page Attributes.” Click on the dropdown menu for Template, and select the template you just created. This will call up the code that you just wrote!

Now, publish the page, and have a look at the finished product. You will see a database listing that now conforms to your WordPress theme, with no need for extra styling!

Here is what it looked like in mine:

Overambition?

http://youtu.be/nhjGoaKf52s

Luckily, I don’t feel like I need Homer’s lesson, although there were moments.

For this week, I decided to try not just embedding a map into a webpage, but into an Omeka site.

A bit of background: for Clio 2 I created an online exhibition, using Omeka, chronicling the journey and visit of the Mexican leader Antonio López de Santa Anna to Washington in 1837. On one page, I had a map showing the route that Santa Anna and his four companions (one Mexican, three Texian) took through the United States.

That map, however, was just a static map. I had planned, as some of my classmates did, to put coordinate points to correspond to different pages on my site. In the end, though, I simply ran out of time (thankfully Dr. Petrik gave me an A anyway!), and left the map as-was.

Since I had basically no experience with either Omeka or PHP when I did the project, I made some errors; e.g., modifying pages in their original folders and not in folders specifically for the theme–a correction I learned this summer at THAT Camp. So when I updated Omeka in September, my customized page layouts were gone–thankfully I had backed them up beforehand, though.

Thus, for the last two months, there has been a caveat on my homepage that the site’s layout had some issues. Here’s what the map page looked like:

The broken page, before I was able to fix it.

Luckily, I was able to fix it–the PHP I learned in class helped me understand where I had gone wrong, and how to use Omeka’s nice documentation to fix it. So during the hurricane, I fixed it:

The journey map after I managed to fix it.

So, then to tackle changing that static map into a Google Map.

I had previously gone through Laura’s excellent tutorial, plotting out the journey (using the diary of Juan Nepomuceno Almonte, a Mexican Army colonel and Santa Anna’s translator for the journey) and warping the same 1837 map I had used originally.

My first step was seeing, then, if I could get the map to work in a separate page. I did; this page draws on the style of my Omeka site. It’s not perfect–the map warping turned out, well, too warped–but it’s close.

Here is my code:

<!DOCTYPE html>
<html>

<title>Santa Anna Goes to Washington: Historic Map</title>
	 <link rel="stylesheet" type="text/css" href="http://davidmckenzie.info/projects/themes/santa-anna/css/style.css" />
	 
    <script type="text/javascript"
      src="http://maps.googleapis.com/maps/api/js?key={my API key}&sensor=false"></script>
      <script src="http://davidmckenzie.info/clio3sandbox/maps/santa-anna-map.js">
    </script>
  </head>
  <body onload="initialize()">
    <div id="map"></div>
  </body>
</html>

Then came getting the same thing into my Omeka site. That, I am still trying.

When I inserted the original map image into that page, I simply put the regular HTML code for an image into Omeka’s text editor for that page, using the HTML option. But I realized that inputting the Java script calls might be an issue, since in the regular HTML page, they are in the head instead of the body. I didn’t want to add them to the head of my Omeka site, as they would be called for every page.

So I tried inserting them into the body of the page.

The next problem: I knew that I couldn’t use the <body> tag to open the function. So I searched around, and came upon this forum answer. I tried using the iframe tag.

Here is the code that I attempted to insert into the editor:

    <script type="text/javascript"
      src="http://maps.googleapis.com/maps/api/js?key={my API key}&sensor=false"></script>
      <script src="http://davidmckenzie.info/clio3sandbox/maps/santa-anna-map.js">
    </script>
  
  <iframe onload="initialize()">
    <div id="map"></div>
  </iframe>

Here’s what it spat back out:

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=AIzaSyBu9qoNY_aPuji9GwHNDPDhKIV-tVh1AaY&amp;sensor=false"></script>
<script type="text/javascript" src="http://davidmckenzie.info/clio3sandbox/maps/santa-anna-map.js"></script>
<p><iframe>&amp;lt;div id="map"&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/div&amp;gt;</iframe></p>

However, the thread in that forum response was over two years old, and last referred to Omeka 1.2.something. We’re now above version 1.5 (and I understand a version 2 is coming–looking forward to seeing!). Perhaps that answer is outdated? I tried finding the line to which Sheila Brennan refers in the exhibits.js file, without luck. I even added it at one point.

I found another forum answer with the suggestion to use Neatline for this purpose.

So, I’ve reached an end. Does anyone have any suggestions on how to embed my map into my Omeka site? Do I just need to use Neatline (something I’m at least looking forward to trying)? Or can it be done like it is in a regular HTML page?

Any help would be greatly appreciated!

Playing with new tools

This past week, I’ve spent a bit of time (at least when not dealing with a busy week at work, including leading two walking tours on Sunday) playing around with tools that we learned last week, and looking a bit ahead.

After Sasha and Jeri’s excellent tutorials, I was eager to dive into webscraping tools. I poked around a bit with Wget most, learning different options for bulk downloading. I thought of various historical resources I may want to use, and experimented with how to get that data. I learned, in particular, the importance of the -np (no parent) option, the hard way! I also successfully downloaded just the HTML and image files from a site; I was particularly interested in the HTML files, as they contain many primary sources divided among different pages. Next thing to learn: how to fuse these texts in a bulk manner…

I also tried to use it to back up my own website, with less success. Less success, in this case, means that it downloaded the “index.html” page that my WordPress installation produces… And nothing more. Am I missing something–perhaps I (or Dreamhost) have set my security settings too well? Then again, perhaps I shouldn’t complain about that.Is there an issue with downloading, say, a CMS? Should I be using something else (e.g., Python) in this case?

Python, and generally writing more complicated scripts than one command at a time with Wget, is another area in which I need to experiment more. For the end goals of which I could think this week, Wget seemed to work. Mostly.

At some point I would also like to write my own Zotero translator. I spent some time thinking of the kind of item for which I’d like to write a translator (ironic, since I can think of plenty of times where lack of a translator frustrated me), and so haven’t at the moment. Likely, I will follow Sasha’s lead and write one for my own data pages about the claims that I’m researching. The first step in that process will, of course, be building said pages…

I also thoroughly enjoyed Julie Meloni’s tutorial on using APIs (in three parts: 1 2 3). It was written for someone at my level: an advanced (debatable) beginner and non-programmer.

That inspired me to get my own Google Maps API and do some very, very basic playing. By very basic, I mean taking Google’s basic map page and plugging in my own coordinates and API. Here is the result, focused in on my former place of employment, the Alamo.

As happened last week, learning these new tools helped me think more about what product I want coming out of this class. In developing my free-standing database site, I’d like to include maps–both for the aggregate data, as well as for each individual claim. For the aggregate data, I’m not sure yet what mapping application I would use–I look forward to the next two weeks, when we learn about what’s available and what works for what. For each individual claim, I would like to include maps for my four geographic fields: home port of ship (when applicable), place of incident, destination port, and destination of goods. Google Maps might be best for that, although the jury is still out.

A side note, along the lines of my individual data pages: I’d like to learn how to hide portions; e.g., the empty fields. If that is even possible. Hint, hint.

So, that’s where things stand. I look forward to learning more about mapping and APIs from Laura.

Small steps and the big picture

This week for Clio 3 I recovered from last week’s angst–at least mostly. Working on my PHP CRUD (more on that below) and looking at the tutorials for what we’re doing next in class got me thinking both about the small steps and the bigger picture.

Small Steps

First, the small steps.

After class, I realized that my approach to tackling my PHP CRUD  (create, read, update, delete) was off, to put it mildly. In creating my form for entering new data or updating my database, I followed a few examples, working to customize for my own needs–and picking up more PHP with it.

I went through it in a systematic way–just using the wrong system. I went through each portion of the file for all 37 or so variables (perhaps the first problem was having 37 variables). For example, one night I created all of the blanks for data entry, and tried (unsuccessfully) to create the menu for those fields already populated (e.g., people). The next night, I went through all of the edit scripts. Then I tried the new record portion. But doing it this way meant that it never actually ran. It got too complicated–both from my own PHP ineptitude and my surfeit of variables–before I could get it to that stage.

So after I threw my hands up in despair, I tackled CRUD again from the ground up. I approached it in what I’ve learned is the better systematic way: I created a very basic form first, with a few variables. I did everything I needed to get that functioning fully. Then I added more variables, and got those to function fully.

I started out with the small steps: the basic data entry parts. And lo and behold, it worked! I now have a functional, albeit far from complete, CRUD going. If you want to add a claim, I have the database living locally, so feel free to play. I’ll eventually password-protect the editing and deleting functions, but for now, I’m just glad to have them, and glad that others can see.

The next steps are, though, the harder ones. I need to figure out my menus…

Perhaps that will be the next step. Or perhaps it’s time, now that I’ve gotten a functional form using procedural PHP, to make one using object-oriented PHP. Like others in the class, after last week’s class and the tutorial, I understand the idea behind object-oriented PHP. Being that I still want to keep roughly 37 variables, if not more (see below), I’m thinking that will be the way to go by the time I turn this into my final project.

But I just don’t feel in a position to start implementing object-oriented PHP for this particular task. If others want to do so and there is time in class, perhaps a “crash course” for our specific tasks?

And the Big Picture…

This brings me to the question that I’m guessing the two people who got this far might have: 37 (or so!) variables?! Is this guy crazy? Well, yes, and likely, yes.

Last week’s frustration got me thinking about what I’m doing with this database. Specifically, what do I want my final project to look like, and how will it serve me (and the broader history profession) in the future?

Having reached this point in the semester, I’ve abandoned my original idea of having my final project reside in Omeka. It simply doesn’t work for what I’m trying to do.

So instead, my final project will be a stand-alone database. My end goal remains the same: using information that resides in U.S. citizen claim files against Mexico as a window into the interactions of the two countries on the ground before they went to war in 1846.

The information in many of the claim files at the National Archives is incredibly rich–useful beyond simply analyzing the claims themselves. All the files contain memorials, stating detail about the incidents for which the claimants sought compensation. But in order to advance their claims, these U.S. nationals submitted extensive supplementary documentation. Several ship manifests reside in these files, listing specific quantities of goods being traded–along with their ultimate destinations. The claimants who visited or even resided in Mexico detailed their activities there.

My goal is to capture as much of that information as possible in a systematic way, then analyze it for my dissertation. What types of goods were most traded? To and from where? How did that change over time? Where were people from the United States most active in Mexico? In what kinds of activities did they engage? What money was at stake? Who were the people connecting with Mexico? Where were they from? Where did they reside? How old were they? Answers to those questions–and many more–reside in this collection. While this collection in no way presents a comprehensive view of the activities of U.S. citizens with regard to Mexico, it does provide a snapshot. It provides a dataset that, at least at this early stage in my research, I’m guessing I would be hard-pressed to find elsewhere.

As such, that is why I chose to work with this dataset, and why right now I have roughly 37 variables. Likely I will end up with more, not less.

So, what will my final product be? As mentioned above, it will be a standalone database. Users will be able to search or browse the database, and run queries. I will provide maps and visualizations as I do them. One model for what I’m thinking is Jean Bauer’s Early American Foreign Service Database. Likely, I will include digitized versions of the memorials and supporting documentation in a separate Omeka collection.

So, that’s where things stand now. Any comments are most welcome!

Oh CRUD… crud crud crud

That is about how CRUD is making me feel at the moment. Creating my data entry form continues to vex me this week.

I am feeling more caught up, overall. I’ve created my listing page, albeit with still non-functional links. Here is the code. However, I still need to figure out–if it is possible–how to list the multiple people with each case, rather than how it is listed now. Is it?

I also created my query page, with a few queries coded in. Here’s the code for that.

I’ve even managed to get my listing page and my query page into a pretty format in WordPress.

But CRUD… Making my full data entry form is what has vexed me. I’ve been able to do a simple one–one that works, one that inputs basic information. But taking that and making it into something larger–and more useful for my purposes–is what’s getting me. I’ve gone through Megan and Sasha‘s forms and posts, but am still having trouble.

Here is the code of where I am so far, knowing that I still need to get in some parts. Perhaps it’s the complexity. I’m getting inputs for 37 variables here. I started with baby steps–putting in all of the variables, trying to get the renderForm function, trying to get the menus, working on the ending functions. Perhaps the number of variables is what’s getting me here, and what I’m asking this form to do. I’m not sure. I can’t get it to run yet, though, so am having a hard time debugging.

So that’s where I am at the moment, before class. If anyone has any thoughts about whether I’m on the right track, and whether I should start off with a simpler form–not being so ambitious as to try to get almost all of my variables covered (there are even more not covered in here)… Well, I’m all ears.

I should add that I realize I haven’t gotten to all of the bottom parts, and that’s perhaps why it’s not running yet. Still learning how to get it to work…

In the meanwhile, I’ll look forward to learning more with Java tomorrow night. And sit back knowing that my presentations are done… :)

Presenting WordPress

This week for Clio 3, I’m presenting on WordPress–the platform on which I’m writing right now. As we’ll discuss in class, though, it’s so much more. WordPress is, indeed, a full content management system.

To give my classmates a preview of what I’ll be doing:

  • First, a Prezi (which you are free to browse) giving a bit of explanation of WordPress and its structure. The infographic that I tweeted shows things nicely; I’m going into a bit more detail.
  • Next I’m talking specifically about pages in WordPress, giving an explanation of them, and a brief overview of creating a custom page in your template. To do that, I’m going through the PHP of an individual page (including slight modifications I made), and using one of my own examples. I’ll show a bit of how we might do some more sophisticated things, and question if we want to do all of that to make one specific page… It may be useful for having more such pages, though.
  • I’ll also talk about important aspects of WordPress themes–including some rules that I’ve broken and things that I need to correct.
  • Finally, I’m talking about linking your own database into WordPress. As I discovered, there are some sophisticated ways to do this, even involving two plugins. In the end, though, I went for what might be a simpler way, one that did not involve copying my extant database. Why? I didn’t want there to be an extra copy, and I knew how to link to the copy that I already have on my server. Plus, I like having the self-contained database. This involved creating a special type of page and putting in the PHP that I did for my basic listing of claims (original). Here’s what the same page looks like placed into WordPress. I’ll show you how I did that in my presentation (here’s the code, with my login info redacted).

Since Sasha will also be presenting (on Omeka), the presentation will be short, and thus general. What I learned in preparing this presentation: you can do a lot with WordPress, and since it’s so used, people have done a lot with it. So my goal is to give everyone an idea of its basic structure, and show a couple of small things you can do with it. I hope this will then help everyone to play on their own with it. 

If there is anything else someone wants to know, please don’t hesitate to comment. I’m working through the day but will at least try to touch upon it.

And thus, I will have done my two presentations for the class. Since I was silly enough to do my presentations two weeks in a row, with a West Coast trip between them, I got behind in a couple of other things; thankfully I am again off work on Monday. I’ve finally normalized most of my database, and added everything into the joiner tables. It’s now ready to take data entry… Once I get a more sophisticated form up and running. For now, I have this, which populates one of my tables.  My next goal: using Sasha’s excellent tutorial, create a complete data entry form. Thankfully, I am off on Monday, and have no travel planned until Thanksgiving.

In the next couple of weeks I will also be creating tutorials based on my presentations for Programming Historian, and contributing resources (thank you Erin for setting this up!) to the class site.

So that is where I am. This time, the presentation will be a lot shorter (I promise!), and I will not be running on 2.5 hours of sleep, and a full day of work (including a presentation to a board committee), before it!

See everyone in class.

It’s 3 a.m. … Do you know where your CSV columns are?

Tomorrow, or technically today, I’m presenting in Clio 3 on Data Manipulation.

As Professor Gibbs and I defined it on Monday, my presentation on this potentially broad topic is twofold:

  • Using SQL commands in PHPMyAdmin to merge and split fields; e.g., merge or split names;
  • Using PHP to switch a CSV file’s date format into an acceptable one for input into a MySQL database.

The first is one with which I feel rather comfortable, and ready to present.

The second, on the other hand… I spent a few hours last night dealing with that (and a bad allergy attack), and I’ve spent all evening tonight on it. After a lot of trial and error, I have much of it working. I can get the file open, and even write back into it. The problem is the middle–switching the order of the dates.

Here is what I have:

The middle parts are the problem.

I am most thankful to this blog post by Evan Cordulack, an American Studies graduate student at William & Mary; after looking at many sites that gave me parts of what I needed, his helped me crystalize most of what I needed.

I tried a few different things: getting slightly familiar with PHP functions (via these two posts that gave functions for changing order of numbers), and using Sasha’s code for her form. The latest version (as posted below, next to the original) reflects Sasha’s code (thanks for going over it with Megan and me on Monday! Hey, look, alliteration!).

I get the feeling that part of my issue is trying to change the data in just one column. Here’s what arouses my suspicions: I get a variation of the jumbled data each time I try.

So… I’ve reached a point where I’m not sure what else to do. There’s something that I’m clearly missing here. Since I’m having too hard of a time figuring out what I’m doing wrong in that middle part, I’m writing this post. Any suggestions are most appreciated.

Dr. Gibbs–if I am able to get off work early (a big if), will you be around? Otherwise, may I make figuring this out part of my presentation? :)

This is what the CSV file originally looked like. I stripped out everything else except for the case number.

Eeep. Other times, it’s changing my initial numbers.

Misrepresenting plantation life

Today’s Washington Post Magazine contains an interesting story about the deterioration of the mansion at Carter’s Grove, a 1750 James River plantation whose opulent mansion now faces ruin due to neglect. This story, which I would otherwise recommend, begins with wrong history that perpetuates plantation nostalgia and stereotypes about Native American savagery.

The lede describes the exquisite detail of the plantation master’s mansion, considered one of the finest examples of plantation architecture. The author then states that Carter Burwell, of the Virginia gentry Carters, wanted his mansion “to awe visitors with physical evidence of the bountiful riches that could be wrung from the New World wilderness.”

This sentence is problematic, to put it mildly. For one thing, the writer ignores and/or mistakes from what, or more accurately whom, Burwell and his fellow gentry extracted their wealth. While an English visitor in 1750 may have thought that the Virginia Tidewater was a wilderness, what could legitimately be considered that loaded term was much further west by then.

Most importantly, this statement, combined with the lede, romanticizes plantation life. Burwell wrung his wealth–note the article’s passive voice–from the enslaved persons (47 in 1783) who lived and toiled at Carter’s Grove every day for undernourishing rations and pitiful housing.

Sadly, this is not the first time I’ve seen such romanticization of plantation life in The Post‘s pages. Last year the paper ran a travel story about a 1778 plantation-turned-inn near Orange, Virginia, where the writer imagined herself and her husband as “lord and lady of the manor,” talked about the other “buildings” on the “estate,” and included a joke that a mannequin in a tux was “the original butler.” Never mind that while Virginia’s gentry fancied themselves as English, they were running (sometimes) profitable slave-labor operations; some of the buildings on the plantation may be former slave quarters, if such flimsily-built housing even survives; and that the original butler would not be the well-paid and attired Mr. Jeeves but an enslaved person.

This year’s magazine story further presents a faulty interpretation of Virginia’s past when it discusses Wolstenholme, a colonial settlement that “was destroyed during a native Powhatan massacre of English settlers in 1622.” The Encyclopedia of Virginia‘s blog tackles this point. The individual act could be described as a massacre, as it was the opening act of a war. The Powhatan leader Opechancanough led his tribe in an attack upon English settlements, killing hundreds of men, women, and children. Again, though, the context that the article’s statement lacks is important. The Powhatans’ 1622 uprising came after 15 years of continuous depredations on the part of English colonists. Omitting that portion of the story perpetuates the trope of savage Indians.

Both articles are not specifically about the history of the places. This week’s magazine story focuses on the destruction by neglect of what is not just an architectural gem but a significant archaeological site. I would otherwise recommend it as an interesting look at historic preservation issues. To be fair, the author does write further in the article about the former slave quarters, formerly maintained (along with the big house) by Colonial Williamsburg, and mentions excavations of a Powhatan village on the site.  Meanwhile, the travel story from last year is a light-hearted look at an inn.

Nonetheless, the tone of both of these stories presents a whimsical look at plantation life–a life that was hardly whimsical for the majority of a plantation’s inhabitants. The historical pictures presented in both stories lack context, perpetuating toxic myths that form the heart of this country’s fraught racial and ethnic relations.

I realize that the writers of both stories were likely working with limited word counts, and the scopes of their stories were beyond these historical statements. But I don’t think I’m going out on a limb saying many more people will read these articles than will read the latest monographs on colonist-Indian relations or slavery in colonial Virginia. As such, these statements matter. It behooves any writer to get his or her history right.

Update: The Encyclopedia Virginia’s blog rightfully responded to this post by pointing out the important difference between getting history right and certain interpretations of history right. An important distinction here, and one that the Encyclopedia Virginia makes well. Thanks!

Informal education, museums, and the Peace Corps

“Peace Corps and the Alamo. I never thought I’d hear that combination.”

That was the reaction of a professor several years ago when I mentioned where I had worked. In March, when I attended the Symposium on Informal Learning, sponsored by the American Association of Museums and The George Washington University Museum Education Program, I remembered that statement.

Listening to the speakers discuss informal education and learning (related but different concepts) reminded me how much my experience in El Salvador with the Peace Corps has overlapped with the career I’ve begun in the museum world. Yet to many, this overlap has seemed surprising. Perhaps this stems from seemingly (at least to my own eyes) little overlap in personnel. In my short time in the Peace Corps, I met no one who was planning a museum or public history career. Although I’ve heard of people in museums and public history who once served in Peace Corps, I haven’t yet met any in person (although I mutually tweet with a Returned Peace Corps Volunteer who is in a library program).

Thus, I share my experiences here in hope of provoking dialogue and connections between museums and the Peace Corps, both of which are engaged in the common objective of creative education outside of a classroom setting and share a lot more in common than may meet the eye.

My initial encounter with informal education

Although I had worked as a history interpreter at the Alamo for several months prior to leaving for El Salvador, Peace Corps training was the first place that I encountered the term informal education.

Perhaps not surprisingly, Peace Corps strongly emphasizes that concept. Many volunteers–in my case, all of my training class besides a 56-year-old engineer–are either fresh out of college or a few years removed. We had spent most of our lives in the formal education system, yet were going to  work with people who often had little contact with their country’s formal educational system.

In my community, many adults had not gone past early elementary school. But lack of education does not mean lack of intelligence. During the next several months I interacted with some of the smartest people I’ve met in my life. Many people–whether Salvadoran campesinos (country folk, loosely translated) or gringos with multiple degrees–do not always learn best in formal settings. Informal education does not mean dumbing down; it simply means teaching with different, “informal,” methods.

So, to reach our audiences, we had to break the habits we had acquired from the formal education system. Gone were lectures. In El Salvador, we gave charlas (“chats,” as compared with “talks”), often at meetings of various community organizations.

Although I didn’t realize it until I returned to the Alamo after early-terminating from Peace Corps, I had also been engaging in informal education there. I have done the same in my museum internships and jobs since. After all, much of what a museum does is informal education, whether it be through lectures, tours, exhibitions, new media activities, and even publications.

Commonalities

Thus, based on my experiences of 10 months in the Peace Corps and now nearly 10 intermittent years in the museum/public history field, I offer some more specific commonalities, with anecdotes to illustrate the points. Since my M.A. is in Museum Studies, and I have not held a specific museum education job (although my jobs have involved some of the same functions), this is by no means a comprehensive list, just some examples that come to mind.

Interactivity

This is the most basic, and general, idea of informal education. The talking head, in both museum settings and the Peace Corps, is the kiss of death to learning. Informal education in both settings is interactive; at its most basic, a dialogue between educator and audience. In Peace Corps, we were rightfully admonished not to be up in front of a group just yakking away, but to engage the audience. This could be through any means, but the most important thing was having a dialogue–a charla.

Guided discovery

One form of interactive informal education that I’ve seen in both museums and Peace Corps is guided discovery–the idea that we guide our audiences to the learning objectives, rather than just telling them. In Peace Corps, volunteers are trained to fade into the background and guide their audiences.

For example, in my community, people complained about how long and scattered community council meetings could be–so much so that it was a disincentive to attendance (other volunteers reported the same). So I decided to try a charla on parliamentary procedure. It was a challenge; parliamentary procedure is not easy to teach in a classroom, much less an informal setting. So, based on what I had learned in training, I worked with that particular meeting’s attendees to draw up rules for how to conduct meetings more efficiently. I put up a piece of butcher paper and worked with the community members to create two lists: essentially, characteristics of good meetings and characteristics of bad meetings. I asked some leading questions. Even when I didn’t, people came up with great suggestions. In the end, we had a list that community members, not the gringo, had created.

Just the same, in museums we guide people to come to the conclusions we are trying to teach. During a tour, rather than telling people what is on a building, we have them look for themselves. Then, we guide them to deduce the building’s history from those clues. Thus, our audience members feel like they have come up with the solution for themselves, and are more likely to have that lesson sink in.

Physical motion, even games

Peace Corps training strongly emphasizes games; I was lucky to have a program director who had co-authored an entire book on games to use in water, health, and sanitation education. What I saw there, and have since seen in museums, convinced me that games are not just for children.

In my community, I watched a nongovernmental organization worker use a game from that book to great effect to teach about the importance of preventative health practices–not always well-known in rural El Salvador. She gave each participant a certain amount of “money.” Then she read out different scenarios for the next several days, reflecting decisions people could make about preventative health. Each participant either received more money (for a day’s work) or lost money (for expenses) for each day. For example, someone did not wash his/her hands before handling food and got amoebas (not a pleasant experience). The person lost a day’s work (in a country where sick leave is rare) and also had to buy medicine. Someone else who did practice preventative health, meanwhile, gained a day’s wage. In the end, the person who had taken the most responsibility for prevention had the most money.

Sure, she could have gotten up and just lectured on the importance of preventative health. But by showing it through this game, she drove the point home; the followup discussion clearly reflected that.

Just the same, in museums we frequently have people act out scenarios. There has recently been a great deal of discussion about gaming in learning–not just in museums, but broadly. Participants in that discussion should look to the Peace Corps for inspiration; Peace Corps has been using games to teach for decades.

Final thoughts

I hope this post might provoke dialogue between museums and the Peace Corps, two of the most established types of informal education institutions. In my brief experiences, I’ve seen a lot of connection between their methodologies. Museum educators would make great Peace Corps volunteers, and vice versa. Both have a lot to learn from each other. I hope that both will do so.

I hope that in the future, people won’t be so surprised when I say that I’ve served as a Peace Corps volunteer and made a career in museums.

Do you have experiences in informal education, whether in the Peace Corps, museums, or another setting? Please share those in the comments. I would love for people with more experience in both to compare notes.

Older posts Newer posts