LetterWalk.cgi: Difference between revisions

From XPUB & Lens-Based wiki
 
(19 intermediate revisions by the same user not shown)
Line 19: Line 19:
print "</body></html>"
print "</body></html>"
</source>
</source>
[[techdazecgi:letterwalk_01.cgi | See this running]]


== Version 2: Select-a-letter ==
== Version 2: Select-a-letter ==
Line 62: Line 63:
print "</body></html>"
print "</body></html>"
</source>
</source>
[[techdazecgi:letterwalk_02.cgi | See this running]]


== Version 3: LeTterCLouD ==
== Version 3: LeTterCLouD ==
Line 69: Line 71:
To start, we need to actually do the counting to get the "data" we need to make the sizes. ... Recall the "histogram" example from [[ThinkPython]], exercises 11.2 - 11.5.
To start, we need to actually do the counting to get the "data" we need to make the sizes. ... Recall the "histogram" example from [[ThinkPython]], exercises 11.2 - 11.5.


=== Version 3.1 ===
=== Counting words per letter ===


So now let's use python to count how many words begin with each letter, and display the results in very simple HTML.
So now let's use python to count how many words begin with each letter, and display the results in very simple HTML.
Line 97: Line 99:
"""
"""
</source>
</source>
[[techdazecgi:letterwalk_03_1.cgi | See this]]


== Version 3.2 ==
=== Visualizing the data ===


To do the scaling of the text size, we will use the concept of [[Rank and Share | rank]] to calculate the font size of each letter.
To do the scaling of the text size, we will use the concept of [[Rank and Share | rank]] to calculate the font size of each letter.
Line 104: Line 107:
<source lang="python">
<source lang="python">
#!/usr/bin/python
#!/usr/bin/python
import cgi


fs = cgi.FieldStorage()
print "Content-type: text/html; charset=utf-8"
letter = fs.getvalue("letter", "a")
 
print "Content-type: text/html; charset=utf8"
print
print


print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
print "<html><head><title>letterwalk</title></head><body>"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>letterwalk</title>
</head>
<body>
"""


lettercounts = {}
lettercounts = {}
Line 145: Line 135:
   print """<span style="font-size: %dpx">%s</span>""" % (size, l)
   print """<span style="font-size: %dpx">%s</span>""" % (size, l)


print """
print "</body></html>"
</body>
</html>  
"""
</source>
</source>
[[techdazecgi:letterwalk_03_2.cgi]]


== Version 4: Type by letter ==
== Version 4: Type by letter ==
See [[LetterType.cgi]]


We now want to allow the user to actually type a word by clicking on the letters. The simplest way to do this is to use two variables for the "state" of the page, one to reflect the "current word" (the result of all previous typing), and again a variable to reflect the single letter that the user has (just) typed. In this case we'll call this "addletter" to emphasize the idea that when the user selects a letter, it gets added onto the current word.
We now want to allow the user to actually type a word by clicking on the letters. The simplest way to do this is to use two variables for the "state" of the page, one to reflect the "current word" (the result of all previous typing), and again a variable to reflect the single letter that the user has (just) typed. In this case we'll call this "addletter" to emphasize the idea that when the user selects a letter, it gets added onto the current word.
Line 172: Line 162:
print
print


print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
print "<html><head><title>letterwalk</title></head><body>"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>letterwalk</title>
</head>
<body>
"""


print "<h2>%s</h2>" % curword
print "<h2>%s</h2>" % curword
Line 206: Line 188:
   print """<a href="?curword=%s&addletter=%s"><span style="font-size: %dpx">%s</span></a>""" % (curword, l, size, l)
   print """<a href="?curword=%s&addletter=%s"><span style="font-size: %dpx">%s</span></a>""" % (curword, l, size, l)


print """
print "</body></html>"
</body>
</html>  
"""
</source>
</source>
[[techdazecgi:letterwalk_04.cgi]]


== Version 5: Letter cloud for the "next letters" ==
== Final Version: Letter cloud for the "next letters" ==


Finally, we want the letter cloud to reflect the relative frequency of the "next letters" so that as someone types, the cloud actually reflects the next possible letters.
Now let's put it all together! Wouldn't it be nice if the "letter cloud" reflected the frequencies of the next possible letters based on what the user has already typed. In this way, the script will "lead" the user towards different possible words.


Also, note the addition of a "start over" link (using href="?") to clear the current state of the game back to the beginning.
Also, note the addition of a "start over" link (using href="?") to clear the current state of the game back to the beginning.
Line 234: Line 214:
print
print


print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
print "<html><head><title>letterwalk</title></head><body>"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>letterwalk</title>
</head>
<body>
"""


print "<h2>%s</h2>" % curword
print "<h2>%s</h2>" % curword
Line 281: Line 253:
print """<p><a href="?">start over</a></p>"""
print """<p><a href="?">start over</a></p>"""


print """
print "</body></html>"
</body>
</html>  
"""
</source>
</source>
[[techdazecgi:letterwalk_05.cgi]]
== Extensions ==
Add a link to an online dictionary site such as the [http://www.wiktionary.org/ Wiktionary] to make it easy to check the definition of a word one discovers.

Latest revision as of 13:06, 10 February 2009

We start with a simple loop to read the contents of a wordlist. In this case, I am using the "words.txt" file that is part of the ThinkPython exercises (part of the "swampy" files you can download).

Version 1: Just display the words (hello world)

To start, we take the minimal python cgi template and add a simple loop that displays the full contents of the file. Note that "words.txt" is a simple kind of database, with one word per line, ordered alphabetically. In many projects, a simple database in the form of a text file makes a good way to quickly get started to produce a workable interface, allowing for a quick test of interactivity.

#!/usr/bin/python
 
print "Content-type: text/html; charset=utf-8"
print

print "<html><head><title>letterwalk</title></head><body>"

f = open("words.txt", "r")
for w in f:
  print w.strip()

print "</body></html>"

See this running

Version 2: Select-a-letter

We add the ability to select and display only those words beginning with a particular letter. We add a variable to the "state" of the page, named 'letter' to represent the selected letter, and use this value to filter the display of the list.

A "legend" is displayed at the top of the page to allow letters to be selected, and also to show the current selection (the current letter gets highlighted). This is a typical pattern in CGI programming.

In creating the links, note the use of Triple Quotes, and Python's String Formatting Operator. These features are extremely useful in generating "template-based" text like HTML.

#!/usr/bin/python
 
import cgi

fs = cgi.FieldStorage()
# get the letter variable from cgi.FieldStorage, default value is a
letter = fs.getvalue("letter", "a")

print "Content-type: text/html; charset=utf-8"
print

print "<html><head><title>letterwalk</title></head><body>"

# Clickable letters with current letter bold
print "<p>"
letters = "abcdefghijklmnopqrstuvwxyz"
for l in letters:
  if l == letter:
    print "<b>%s</b>" % l
  else:
    print """<a href="?letter=%s">%s</a>""" % (l, l)
print "</p>"

# Show only those words that start with the current letter
f = open("words.txt", "r")
for w in f:
  if w[0] == letter:
    print w.strip()
  elif w[0] > letter:
    break

print "</body></html>"

See this running

Version 3: LeTterCLouD

What if we were to indicate the number of words graphically. A simple way would be to let the size of the letter be related to the number of words in the list that start with that word. This is a basic kind of "popularity" scaling typical in "tag clouds".

To start, we need to actually do the counting to get the "data" we need to make the sizes. ... Recall the "histogram" example from ThinkPython, exercises 11.2 - 11.5.

Counting words per letter

So now let's use python to count how many words begin with each letter, and display the results in very simple HTML.

#!/usr/bin/python

print "Content-type: text/html; charset=utf-8"
print

print "<html><head><title>letterwalk</title></head><body>"

lettercounts = {}
f = open("words.txt", "r")
for w in f:
  l = w[0]
  lettercounts[l] = lettercounts.get(l, 0) + 1

letters = lettercounts.keys()
letters.sort()
for l in letters:
  print l, lettercounts[l], "<br />"

print """
</body>
</html> 
"""

See this

Visualizing the data

To do the scaling of the text size, we will use the concept of rank to calculate the font size of each letter.

#!/usr/bin/python

print "Content-type: text/html; charset=utf-8"
print

print "<html><head><title>letterwalk</title></head><body>"

lettercounts = {}
f = open("words.txt", "r")
for w in f:
  l = w[0]
  lettercounts[l] = lettercounts.get(l, 0) + 1

letters = lettercounts.keys()
letters.sort()

(min_count, max_count) = (None, None)
for l in letters:
  if min_count == None or lettercounts[l] < min_count:
    min_count = lettercounts[l]
  if max_count == None or lettercounts[l] > max_count:
    max_count = lettercounts[l]

(min_size, max_size) = (8, 96)
for l in letters:
  rank = float(lettercounts[l] - min_count) / (max_count - min_count)
  size = int(min_size + rank * (max_size - min_size))
  print """<span style="font-size: %dpx">%s</span>""" % (size, l)

print "</body></html>"

techdazecgi:letterwalk_03_2.cgi

Version 4: Type by letter

See LetterType.cgi

We now want to allow the user to actually type a word by clicking on the letters. The simplest way to do this is to use two variables for the "state" of the page, one to reflect the "current word" (the result of all previous typing), and again a variable to reflect the single letter that the user has (just) typed. In this case we'll call this "addletter" to emphasize the idea that when the user selects a letter, it gets added onto the current word.

We add the current word to the display of the page.

#!/usr/bin/python
 
import cgi

fs = cgi.FieldStorage()
curword = fs.getvalue("curword", "")
addletter = fs.getvalue("addletter", None)

if addletter:
  curword += addletter

print "Content-type: text/html; charset=utf8"
print

print "<html><head><title>letterwalk</title></head><body>"

print "<h2>%s</h2>" % curword

lettercounts = {}
f = open("words.txt", "r")
for w in f:
  l = w[0]
  lettercounts[l] = lettercounts.get(l, 0) + 1

letters = lettercounts.keys()
letters.sort()

(min_count, max_count) = (None, None)
for l in letters:
  if min_count == None or lettercounts[l] < min_count:
    min_count = lettercounts[l]
  if max_count == None or lettercounts[l] > max_count:
    max_count = lettercounts[l]

(min_size, max_size) = (8, 96)
for l in letters:
  rank = float(lettercounts[l] - min_count) / (max_count - min_count)
  size = int(min_size + rank * (max_size - min_size))
  print """<a href="?curword=%s&addletter=%s"><span style="font-size: %dpx">%s</span></a>""" % (curword, l, size, l)

print "</body></html>"

techdazecgi:letterwalk_04.cgi

Final Version: Letter cloud for the "next letters"

Now let's put it all together! Wouldn't it be nice if the "letter cloud" reflected the frequencies of the next possible letters based on what the user has already typed. In this way, the script will "lead" the user towards different possible words.

Also, note the addition of a "start over" link (using href="?") to clear the current state of the game back to the beginning.

#!/usr/bin/python
 
import cgi
import cgitb; cgitb.enable()

fs = cgi.FieldStorage()
curword = fs.getvalue("curword", "")
addletter = fs.getvalue("addletter", None)

if addletter:
  curword += addletter

print "Content-type: text/html; charset=utf8"
print

print "<html><head><title>letterwalk</title></head><body>"

print "<h2>%s</h2>" % curword

lettercounts = {}
f = open("words.txt", "r")
for w in f:
  w = w.strip()
  if curword == "":
    l = w[0]
    lettercounts[l] = lettercounts.get(l, 0) + 1
  else:
    if w.startswith(curword):
      # print w
      if len(w) > len(curword):
        l = w[len(curword)]
        lettercounts[l] = lettercounts.get(l, 0) + 1

letters = lettercounts.keys()
letters.sort()

(min_count, max_count) = (None, None)
for l in letters:
  if min_count == None or lettercounts[l] < min_count:
    min_count = lettercounts[l]
  if max_count == None or lettercounts[l] > max_count:
    max_count = lettercounts[l]

(min_size, max_size) = (8, 96)
for l in letters:
  if min_count == max_count:
    rank = 1.0
  else:
    rank = float(lettercounts[l] - min_count) / (max_count - min_count)
  size = int(min_size + rank * (max_size - min_size))
  print """<a href="?curword=%s&addletter=%s"><span style="font-size: %dpx">%s</span></a>""" % (curword, l, size, l)

print """<p><a href="?">start over</a></p>"""

print "</body></html>"

techdazecgi:letterwalk_05.cgi

Extensions

Add a link to an online dictionary site such as the Wiktionary to make it easy to check the definition of a word one discovers.