Thursday, November 14, 2013

Travel Guides for Time Travelers to the 19th Century

About 20 years ago at a used bookshop in Seattle, for $10 I bought an 1859 tourist guide to New York City. The signature of the previous owners (from 1864 and 1950) were inside (click images for full-size view):

It includes a history of New York, the sights a tourist would want to see: government buildings, parks, churches (including reviews of the clergy), etc. Also, hotel and restaurant recommendations, and, of course, information about all the omnibus routes.

A number of these "Stranger's Guides" have been scanned and can be found on the Internet Archive.

The cover page for the London guide is quite entertaining:

Sunday, November 10, 2013

Your own 3D Rotatable Cow!

I work at Tableau Software whose motto is “Tableau helps people see and understand their data.” But it can also be used artistically or even frivolously, such as the 3D rotatable cow I created (use the sliders or “<” and “>” icons to rotate the cow over the x, y and z axes):

How I created it:
  • I found a Wavefront OBJ file defining a wireframe of a cow from somewhere unremembered on the internet. Here’s a large collection of downloadable OBJ files. An OBJ file first lists the vertices of the object in 3D space, then a list of the each face of the object.
  • In Tableau, each edge of the object could be described as the endpoints of of a line, so Tableau needed as its source data an x, y, and z coordinate, and an edge name.
  • I wrote this Python script to convert an OBJ file into a CSV file that Tableau would be able to load. The script is at the end of this post.
  • From this Wikipedia page about the 3D Rotation Group I found the formulae to rotate an object around the x, y and z axis. In a Tableau calculated field, Here is how the x coordinate is changed by rotation on the y axis:
    [X:RotateZ] * cos( ([ThetaY] / 360) * 2 * PI() ) - [Z] * sin( ([ThetaY] / 360) * 2 * PI() )
  • If you download the workbook, it includes a rotatable dodecahedron on another tab. That one you can animate the rotation as there's a theta on the page shelf (as opposed to be a parameter). For the theta, for each row in the CSV file, I repeated the coordinate data with a different theta value at 5° intervals.
  • The previous mentioned Python script to convert an OBJ file to a CSV file suitable for Tableau: 
import sys

def print_line(vertex, edge):
    sys.stdout.write(('%s, %s, %s, "%d"\n') % (vertex[0], vertex[1], vertex[2], edge))

# Column names
print "X, Y, Z, Edge"

lineNum = 0
doneWithV = False
faces = []
vertices = [[]]

f = open(sys.argv[1])

for line in f:
    lineNum += 1
    line = line.rstrip('#')
    line = line.strip()
    if len(line) == 0:
    vals = line.split()
    if vals[0] == 'v':
        if doneWithV:
            print "V after F"
        if len(vals) != 4:
            print "Invalid line #", lineNum

    elif vals[0] == 'f':
        doneWithV = True

edge = 0
for face in faces:
    # Add the first vertex to the end of the list of vertices
    # so there is a line from the last to the first vertex.

    face += [face[0]] 

    for i in range(len(face) - 1):
        print_line(vertices[int(face[i])], edge)
        print_line(vertices[int(face[i + 1])], edge)
        edge += 1;

10 Annoying Answers for 20 Questions

  1. Everything bigger than a breadbox.
  2. Everything that is animal, vegetable or mineral.
  3. Every possible answer you could give for 20 questions.
  4. Yellow.
  5. Hunger.
  6. Happiness.
  7. Midnight.
  8. The answer to the first question (guaranteed win for the first question).
  9. The answer to the 20th questions (guaranteed win for the 20th question, and no other question).
  10. {Nothing you can guess, including {Nothing you can guess}, including {Nothing you can guess, including {Nothing you can guess}} including {Nothing you can guess, including {Nothing you can guess}, including {Nothing you can guess, including {Nothing you can guess}}}, ad nauseum} (The non-answer, and all its recursive possibilities).