28 January 2013

Using TypeScript to Define JSON Data

JSON has gradually been wearing away at XML's position as the primary format for data communication on the Web. In some ways, that's a good thing: JSON is much more compact and readable. In other ways, it's not so great: JSON lacks some of XML's features.

One of these features is document type definitions. For XML, there are a variety of formats (DTD, XML Schema, RELAX NG, etc.) for specifying exactly what your XML data looks like: what are the tag names, possible attributes, etc. JSON is a lot more loosey-goosey here.

Okay, that's not entirely true: there is JSON Schema. I've never known anyone to use it, but it's there. It's awfully verbose, though. (So are the definitional formats for XML, but it's XML  you expect it!)

I was thinking about this the other day, and I realized that there is actually a great definitional format for JSON already in existence: TypeScript! If you haven't heard of it, TypeScript is a superset of JavaScript which introduces optional strict typing. And since JSON is a subset of JavaScript, TypeScript is applicable to JSON as well.

One of the great features of TypeScript is that interface implementation is implicit. In Java or ActionScript, you have to specifically say that a type "implements MyInterface". In TypeScript, if it fits, it fits. For example:

interface List
{
    length: number;
}

function isEmpty(list: List): bool
{
    return list.length === 0;
}

console.log(isEmpty("")); // true
console.log(isEmpty("foo")); // false
console.log(isEmpty({ length: 0 })); // true
console.log(isEmpty({ length: 3 })); // false
console.log(isEmpty({ size: 1})); // Compiler error!

(Note: for some reason that I can't fathom, isEmpty() doesn't work on arrays. Well, TypeScript is still in development  version 0.8.2 right now. Update: I filed this as a bug.)

Note that you can use interfaces even on plain objects. So of course you can use it to describe a JSON format. Here's an example from a project I hope to release before too long:

interface Model
{
    uid: string;
}

interface Name extends Model
{
    citationStart?: number;
    html?: string;
    namebankID?: string;
    root?: bool;
    string?: string;
    type?: string;
    uri?: string;
    votes?: number;
}

interface Taxon
{
    canonicalName?: Name;
    illustrated?: bool;
    names?: Name[];
}

Now, for example, I can declare that an API search method will return data as an array of Taxon objects (Taxon[]). And look how compact and readable it is!

Note that there is one drawback here: there is no way to enforce this at run-time. JSON Schema might be a better choice if that's what you need. But for compile-time checking and documentation, it's a pretty great tool.

24 January 2013

Saving Bootstrap Settings

The popular web page framework Bootstrap recently added a web form whereby you can customize visual settings (color scheme, fonts, etc.). Unfortunately they didn't add a way to save those settings, so if you later decide you need to tweak them and you didn't happen to just leave that web page open, you're screwed. You either have to reinvent them, go from memory, or dig through the generated files and hope you didn't miss anything.

I'm sure they plan to address this eventually, but in the meantime I created some JavaScript code to work around this: https://gist.github.com/4628506

To use this code:
  1. Go to: http://twitter.github.com/bootstrap/customize.html
  2. Run the script in the JavaScript console. (If you don't use a browser with a JavaScript console, you're beyond my help.)
  3. Fill out the customization form.
  4. You can record your settings into an object by running: var settings = record()
  5. You can grab those as JSON by running: JSON.stringify(settings)
  6. You can reinstate those settings later by running: play(settings)
  7. You can save your settings to local storage by running: save()
  8. You can retrieve your settings from local storage by running: retrieve()
I haven't fully tested this, so let me know if you run into any issues.

SIDE NOTE: This is my first gist!



02 January 2013

All Known Great Ape Individuals (Messinian to Present)

Happy 2013, everyone!

Recently I announced a code package I was working on, called Haeckel, for generating vector-based charts related to evolutionary biology. Here's an image I've created using it:

Known Great Ape Individuals
This chart represents all known hominid individuals (Hominidae = great apes, including humans and stem-humans) from the Messinian to the present, erring on the conservative side when the material is too poor to determine the exact number.

If you've been following this blog for a few years you may remember an earlier version of this. I've done a lot of refinement to the data since then. The earlier versions were dissatisfying to me because the horizontal axis was essentially arbitrary. For this version I used matrices from a phylogenetic analysis (Strait and Grine 2004, Table 3 and Appendix C) of craniodental characters to generate a distance matrix, and then inferred positions for other taxa based on phylogenetic proximity and containing clade. This is similar to the metric I used in this chart, except that it incorporates Appendix C, uses inference, and averages distance from humans against distance from [Bornean] orangutans. Don't be mistaken  this is still arbitrary. But it's a bit closer to something real.

Stray notes:
  • I'm pretty sure there are Pliocene stem-orangutans somewhere, right? Might have some work left to do on that data.
  • The dot with no taxon above "Australopithecus" is an indeterminate stem-human from Laetoli. It should probably go further left.
  • The Ardipithecus bubble includes the poorly-known "Australopithecus" praegens. (Although in some runs it moves outside  there's a random element to the plotting.)
  • The Holocene is barely visible up at the top. What a worthless epoch.
  • Homo floresiensis (hobbits) are far to the left of Homo sapiens because I placed them outside Clade(Homo erectus  Homo sapiens).
  • You may recall Lufengpithecus? wushanensis as "Wushan Man", as it was originally placed in Homo erectus. (Hey, it's just teeth.)
  • A couple of fossil chimpanzees, lots of fossil orangutans, but no fossil gorillas. :(
    • (Unless you count Chororapithecus, but that's pre-Messinian. Very pre-Messinian. Suspiciously pre-Messinian....)
  • Look at all that overlap between Homo, Paranthropus, and Australopithecus!
    • I have a feeling, though, that if I added another dimension, Paranthropus and Homo would jut out in opposite directions.
    • Reclassifying Australopithecus sediba as Homo sediba would also decrease the overlap. (Although its position is inferred  actually scoring it might do the same thing.)
    • It's frustrating that the type species of Australopithecus and Paranthropus are also just about the most similar species across the two genera.
  • Kenyanthropus and Praeanthropus have been provisionally sunk into Australopithecus.
  • Should we just sink Orrorin and Sahelanthropus into Ardipithecus? Why not?
  • My guess is that if I added postcranial characters, the stem-humans would all shift right (humanward). Oh, for a good matrix of postcranial characters....
Update
Oh yeah, and if you want a peek at the data, go here.